组件 按需引入原理

import { Button } from 'element-ui'

以Element UI为例,为实现按需引入,需要借助 babel-plugin-component 这个 webpack 插件,并且配置 .babelrc

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

最终转换成:

var button = require('element-ui/lib/button')
require('element-ui/lib/theme-chalk/button.css')

类似转换代码:

//转换代码
export default function (babel) {
  //babel.types
  const { types: t } = babel;

  return {
    name: "import-to-require",
    visitor: {
      //针对import导入语句
      ImportDeclaration(path) {
        //import的source来源是antd
        if (path.node.source.value === "antd") {
          // var _button = require("antd/lib/button");
          const _botton = t.variableDeclaration("var", [
            t.variableDeclarator(
              t.identifier("_button"),
              t.callExpression(t.identifier("require"), [
                t.stringLiteral("antd/lib/button"),
              ])
            ),
          ]);
          // 替换当前import语句
          path.replaceWith(_botton);
        }
      },
    },
  };
}
  • 通过重写路径,精准地引入了对应 lib 下的 Button 组件的 JS 和 CSS 代码了,也就实现了按需引入 Button 组件。

解决组件依赖产生的冗余

  • 由于支持每个组件可以单独引入,那么如果产生了组件依赖并且同时按需引入的时候,会产生重复引入。举个例子,在 element-ui 中,Table 组件依赖了 CheckBox 组件,那么当我同时引入了 Table 组件和 CheckBox 组件的时候,最终引入的包会有 2 份 CheckBox 的代码

解决方式:

  • 解决js冗余:通过webpack配置externals,防止将这些 import 的包打包到 bundle 中,并在运行时再去从外部获取这些扩展依赖
//element ui的方式
var externals = {};

Object.keys(Components).forEach(function(key) {
  externals[`element-ui/packages/${key}`] = `element-ui/lib/${key}`;
});

externals['element-ui/src/locale'] = 'element-ui/lib/locale';
utilsList.forEach(function(file) {
  file = path.basename(file, '.js');
  externals[`element-ui/src/utils/${file}`] = `element-ui/lib/utils/${file}`;
});
mixinsList.forEach(function(file) {
  file = path.basename(file, '.js');
  externals[`element-ui/src/mixins/${file}`] = `element-ui/lib/mixins/${file}`;
});
transitionList.forEach(function(file) {
  file = path.basename(file, '.js');
  externals[`element-ui/src/transitions/${file}`] = `element-ui/lib/transitions/${file}`;
});

externals = [Object.assign({
  vue: 'vue'
}, externals), nodeExternals()];

  • 解决css冗余:对于css部分,用后编译的思想(可以解决按需引入的 JS 和 CSS),即依赖包提供源码,而编译交给应用处理
    • 后编译:指的是应用依赖的 NPM 包并不需要在发布前编译,而是随着应用编译打包的时候一块编译。
    • 后编译嵌套问题:后编译的包所依赖的包也需要显示指定在inlcude中才行,为了解决这个问题,通过这个插件webpack-post-compile-plugin
    • 个人理解:后编译使得编译时机推后,统一编译,使得只编译一次,而不会多次编译产生多份代码。
// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [
      // ...
      {
        test: /\.js$/,
        loader: 'babel-loader',
        // 注意这里的 include
        // 只需要把后编译的模块 A 和 B 通过 webpack 的 include 配置包含进来即可
        // 除了 src 还包含了额外的 node_modules 下的两个包
        include: [
            resolve('src'),
            resolve('node_modules/A'),
            resolve('node_modules/B')
          ]
      },
      // ...
    ]
  },
  // ...
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值