背景
項目使用vue2與element-ui;最近發現項目的部分引入失效了
// babel.config.js
module.exports = api => {
return {
"presets": ['@vue/cli-plugin-babel/preset'],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
};
};
babel-plugin-component 負責將element-ui的引入代碼轉換為部分引入代碼;
全量的element-ui是被誰引入的
這裏我們使用Vue.component這個函數作為切入點;
發現Vue.component對於同一個組件(如ElTooltip)調用了2次;
看到全量引入的element-ui來自於node_modules中的包;
查看了下logic-tree這個包的代碼
// 打包前源碼
import { Button } from 'element-ui';
// 打包後
var _ks_kwai_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! element-ui */ \"../../node_modules/element-ui/lib/element-ui.common.js\");
可以看出包本身代碼沒有問題,是我們在打包時babel-plugin-component沒能在包文件上生效,導致import語句被webpack翻譯為使用了main下的index.js
為什麼babel-plugin-component沒能生效?
可以看出babel-loader沒有去編譯node_modules下的文件。
很好理解,如果所有node_modules代碼都要編譯,會大大增加打包與熱更新時間;
在babel-plugin-component源碼中加入log,發現確實沒有調用
ImportDeclaration: function ImportDeclaration(path, _ref2) {
var opts = _ref2.opts;
var node = path.node;
var value = node.source.value;
var result = {};
if (Array.isArray(opts)) {
result = opts.find(function (option) {
return option.libraryName === value;
}) || {};
}
console.log('hy', value);
...
通過文檔閲讀後,發現參數transpileDependencies可以控制node_modules哪些包需要經過babel
默認情況下 babel-loader 會忽略所有 node_modules 中的文件。你可以啓用本選項,以避免構建後的代碼中出現未轉譯的第三方依賴
transpileDependencies 失效
我們的項目採用pluginAPI來配置vue.config,因此在plugin中加入如下代碼(現狀)
module.exports = api => {
api.service.projectOptions.transpileDependencies = [
'logic-tree'
];
api.service.projectOptions.productionSourceMap = false;
...
}
但是加上後發現沒有生效;通過調試與源碼搜索發現transpileDependencies的使用方為@vue/cli-plugin-babel,也是一個plugin,而且他的調用順序先於我們的plugin,此時transpileDependencies還未初始化,效果如圖
還是需要一個vue.config.js,我這裏建立一個空的vue.config.js來配置transpileDependencies參數
// vue.config.js
module.exports = {
transpileDependencies: [
'logic-tree'
],
};
babel-plugin-component 報錯
這次打包babel-plugin-component終於生效了,但是卻引起如下報錯。
查看了下logic-tree/dist/index.es.js源碼
import{Button as t,Tooltip as e}from"element-ui";var r=Object.freeze(Object.defineProperty({__proto__:null,get default(){return No}},Symbol.toStringTag,{value:"Module"})),n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:...
發現這個包的es版本代碼,將Tootip起了個別名e,babel-plugin-component沒有兼容別名。
解決辦法:將 babel-plugin-component 替換為 babel-plugin-import;
至此,問題解決,完。
附錄1 關於調試
注意:調試之前需要先清除 node_modules/.cache,否則plugin代碼不會調用
追查問題過程中涉及對vue-cli-service整個打包過程的調試,之前的調試方案一般藉助npx --node-options='--inspect-brk',結合chrome://inspect頁面進行調試,例如
PROJECT_PATH=/root-project/custom-widgets/customization-table npx --node-options='--inspect-brk' /root-project/tools/kwaibi-cli/node_modules/.bin/vue-cli-service build --target lib --name kwaibi-custom-widget-plugin/customization-table@0.9.82 --dest /root-project/custom-widgets/customization-table/dist /root-project/custom-widgets/customization-table/src/main.ts
但是node端經常會fork child-process,這時候我們只調試主進程是沒有意義的,還需要找到子進程fork的地方手動加上inspect參數才能對子進程進行調試
vscode參數autoAttachChildProcesses幫助我們節省了這些工作。
進入vscode調試功能,配置launch.json如下
{
"configurations": [
{
"type": "node-terminal",
"name": "kwaibi-cli node",
"request": "launch",
"command": "PROJECT_PATH=/root-project/custom-widgets/customization-table /root-project/tools/kwaibi-cli/node_modules/.bin/vue-cli-service build --target lib --name kwaibi-custom-widget-plugin/customization-table@0.9.82 --dest /root-project/custom-widgets/customization-table/dist /root-project/custom-widgets/customization-table/src/main.ts",
"autoAttachChildProcesses": true,
"cwd": "${workspaceFolder}/tools/kwaibi-cli",
"env": {
"PROJECT_PATH": "${workspaceFolder}/custom-widgets/customization-table"
}
}
]
}
效果如圖