предисловие
Наггетсы уже давно не булькают.Конечно на то есть причины.В марте мне сделали операцию и я попросила больничный на 3 месяца. После операции я лежала, из-за травмы позвоночника, под защитой корсета, в апреле начала вставать и заниматься спортом.
Перед аварией компания готовилась сделать внутреннюю библиотеку пользовательского интерфейса, поэтому я изучил некоторые решения библиотеки пользовательского интерфейса с открытым исходным кодом, и вот краткое изложение и обмен.
Как каждая библиотека компонентов делает это?
они обычно используютwebpack
илиrollup
Упакованный для создания входного js-файла, этот файл обычно используется, когда вам не нужно импортировать библиотеки компонентов по запросу.
Напримерiview
библиотека компонентовdist
в каталогеiview.js
документ.
import ViewUI from 'view-design';
// 引入了整个js文件,里面可能包含了一些你不需要的组件的代码
Vue.use(ViewUI);
Другой примерrsuite
библиотека компонентовlib
в каталогеindex.js
документ.
// 即使你没有使用其他组件,也会引入一整个js文件
import { Button } from 'rsuite';
function App() {
return <Button>Hello World</Button>;
}
Если нам не нужно вводить все компоненты, мы не можем изначально упаковать код компонентов в js-файл. мы можем напрямую использоватьbabel
или с помощьюgulp
к исходному коду библиотеки компонентовsrc
Каждый файл в каталоге компилируется напрямую и записывается в целевойlib
содержание.
// 使用`gulp-babel`对源代码的目录进行编译
function buildLib() {
return gulp
.src(源码目录)
.pipe(babel(babelrc()))
.pipe(gulp.dest(目标lib目录));
}
Скомпилированная структура каталогов точно такая же, как структура каталогов исходного кода, но код компонента был обработан Babel.
В настоящее время мы можем импортировать библиотеки компонентов по запросу. Но в бизнес-кодеimport
Код должен быть изменен. мы начинаем сrsuite
Например, библиотека компонентов. Если мы просто хотим использоватьButton
компонент, нам нужно указать, что только импортlib\Button
Под содержаниемindex.js
документ.
// 只引入 node_modules/rsuite/lib/Button/index.js 文件
import Button from 'rsuite/lib/Button';
Это действительно довольно неприятно, но, к счастью, уже есть готовые решения,babel-plugin-import
плагин. Предположим, наша упакованная структура каталогов выглядит так, как показано ниже.
нам просто нужно.babelrc
Сделайте следующие настройки.
// .babelrc
{
"plugins": [
[
"import", {
"libraryName": "react-ui-components-library",
"libraryDirectory": "lib/components",
"camel2DashComponentName": false
}
]
]
}
Плагин babel автоматическиimport { Button } from '组件库'
Перевести вimport Button from '组件库/lib/components/Button'
.
Такbabel-plugin-import
Как это делается?
Механизм реализации babel-plugin-import
Исходный код babel-plugin-import я не изучал внимательно, а читал только бегло, не очень хорошо понимаю многие детали, если есть ошибки, то дополняйте.
Прежде чем разобраться в исходном коде babel-plugin-import, нам также необходимо понять концепцию ast и посетителя, эти концепции рекомендуется прочитать каждому в этом руководстве.Руководство по плагину Babel
Исходный код babel-plugin-import определяетimport
посетитель узла (babel
При обработке исходного кода, если вы столкнулисьimport
заявление, будет использоватьimport
пара посетителейimport
узел кода для обработки)
Давайте сначала посмотрим,import
Как выглядят узлы кода в глазах Babel
Дерево с правой стороны изображения — это дерево в функции посетителя.path
параметр
ImportDeclaration(path, { opts }) {
const { node } = path;
if (!node) return;
const { value } = node.source;
const libraryName = this.libraryName;
const types = this.types;
// 如果value等于我们在插件中设置的库的名称
if (value === libraryName) {
node.specifiers.forEach(spec => {
// 记录引入的模块
if (types.isImportSpecifier(spec)) {
this.specified[spec.local.name] = spec.imported.name;
} else {
this.libraryObjs[spec.local.name] = true;
}
});
// 删除原有的节点,就是删除之前的import代码
path.remove();
}
}
В нужный момент будет вставлен измененный путь импортаimport
узел
importMethod(methodName, file, opts) {
if (!this.selectedMethods[methodName]) {
const libraryDirectory = this.libraryDirectory;
const style = this.style;
// 修改模块的引入路径,比如 antd -> antd/lib/Button
const path = `${this.libraryName}/${libraryDirectory}/${camel2Dash(methodName)}`;
// 插入被修改引入路径的 import 节点
this.selectedMethods[methodName] = file.addImport(path, 'default');
if (style === true) {
file.addImport(`${path}/style`);
} else if(style === 'css') {
file.addImport(`${path}/style/css`);
}
}
return this.selectedMethods[methodName];
}