rollup打包按需加载的组件

rollup介绍

rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScript 的 ES6 版本中,而不是像CommonJS 和 AMD这种特殊解决方案。( 也有插件可以处理成umd模式 )

rollup最大的亮点就是Tree-shaking,即可以静态分析代码中的 import,并排除任何未使用的代码。这允许我们架构于现有工具和模块之上,而不会增加额外的依赖或使项目的大小膨胀。如果用webpack做,虽然可以实现tree-shaking,但是需要自己配置并且打包出来的代码非常臃肿,所以对于库文件和UI组件,rollup更加适合。

一,安装依赖

npm i rollup –save-dev

二,配置文件

rollup 的配置文件是在 rollup.config.js 中配置的,由于rollup 本身会处理 这个配置文件,所以我们可以使用 ESmodules 语法来写

我们执行 rollup –config 就可以生成打包后的文件了,我们只有带了 –config ,rollup才会执行我们的配置文件,默认是不会执行我们的配置文件的

external属性

使用rollup打包,我们在自己的库中需要使用第三方库,例如lodash等,又不想在最终生成的打包文件中出现jquery。这个时候我们就需要使用external属性。比如我们使用了lodash

 

三,rollup插件

  •  rollup-plugin-terser 用于压缩js代码
  • @rollup/plugin-node-resolve让 rollup 能够识别node_modules的第三方模块。
  • @rollup/plugin-commonjs将 CommonJS 的模块转换为 ES2015 供 rollup 处理。

利用babel来编译es6代码

首先我们先安装babel相关模块:

npm i core-js @babel/core @babel/preset-env @babel/plugin-transform-runtime
设置.babelrc文件

module.exports = {
presets: [[“env”, { “modules”: false }]],
plugins:[
[“@babel/plugin-syntax-dynamic-import”],
[“external-helpers”]
]
}

@babel/preset-env可以根据配置的目标浏览器或者运行环境来自动将ES2015+的代码转换为es5。需要注意的是,我们设置”modules”: false,否则 Babel 会在 Rollup 有机会做处理之前,将我们的模块转成 CommonJS,导致 Rollup 的一些处理失败。

为了解决多个地方使用相同代码导致打包重复的问题,我们需要在.babelrc的plugins里配置@babel/plugin-transform-runtime,同时我们需要修改rollup的配置文件:

babel({
  exclude: 'node_modules/**',    
  runtimeHelpers: true   // 使plugin-tramsform-runtime生效
})  

 

rollup 的优势和缺点

 

优点:

  • 输出结果更加扁平,执行效率更高,
  • 会自动移除未引用的代码(内置了 tree shaking)
  • 打包结果的可读性比较好

 

缺点:

  • 加载第三方模块比较复杂
  • 模块被打包到一个函数中,不能实现 HMR (html-modules-replace)模块热替换
  • 浏览器环境中,代码拆分功能必须依赖 amd 库,

 

打包器选择:

当我们使用第三方插件比较多时,我们选用webpack,当我们写一些自定义插件,库,或者框架的时候(vue、react…),我们使用rollup 作为模块打包器,webpack 大而全,rollup 小而美

 

注意事项

  • node版本最好是10.0.0以上
  • 插件的引用顺序可能会引起报错

 

遇到的坑

1.Babel 7.0.0-beta.56 has dropped support for the ‘helpersNamespace’ utility.

解决方案:

安装babel 6.x

npm install –save-dev rollup-plugin-babel@3

npm install –save-dev babel-core

npm install –save-dev babel-upgrade

 

总体思路:

  • 编写多个组件,暴露各自独立入口
  • 编写整体入口文件
  • 编写打包脚本
    1.     编写打包入口文件列表或者自动获取
    2.     遍历入口分别使用rollup.rolup方法进行打包
    3.     通过内置generate方法获取打包后的数据,fs.writeFileSync创建对应文件
  • 添加自定义打包script(注意运行打包脚本前需要先删除出口文件夹)
  • 配置package.json相应字段
  • 运行命令,打包发布

 

遍历

// 打包模式列表
const formatTypeList = [
  { format: 'umd', min: false, suffix: '.js' },
  // { format: 'cjs', min: true, suffix: '.common.min.js' },
  // { format: 'umd', min: false, suffix: '.umd.js' },
  // { format: 'umd', min: true, suffix: '.umd.min.js' }
  // { format: 'es', min: false, suffix: '.js' }
  // { format: 'es', min: true, suffix: '.es.min.js' }
]
// 创建目录
fs.mkdirSync('lib')
fs.mkdirSync(getAssetsPath('style'))
let packages = []
formatTypeList.forEach(({ format, min, suffix } = {}) => {
  entries.forEach(({ input, output , module }) => {
    packages.push({ min, format,suffix,module, input, output: `${output}`})
  })
})
build(packages)

打包

const { output, suffix, input, format, module , min } = config
  const inputOptions = {
    input,
    external: Object.keys(external),
    plugins : plugins
    // plugins: min ? plugins.push(terser()) : plugins
  }
  const fullName = output + suffix
  const file = getAssetsPath(fullName)
  const outOptions = {
    file,
    format,
    name: module,
    globals: external
  }
  console.log(rollup);
  const bundle = await new rollup.rollup(inputOptions)
  let { output: outputData } = await bundle.generate(outOptions)
  await write({ output: outputData, fileName: output, format, fullName, file })

创建文件

for (const { type, code, source } of output) {
    if (type === 'asset') {
      const cssFileName = `${fileName}.css`
      const filePath = getAssetsPath(`/style/${cssFileName}`)
      // rollup.write(filePath,source.toString())
      !fsExistsSync(filePath) && fs.writeFileSync(filePath,source.toString())
    else {
      const filePath = file
      let codeSource = code.replace(/\s?const\s/g, ' var ')
      fs.writeFileSync(filePath, codeSource)
    }
  }

 

发表评论

邮箱地址不会被公开。 必填项已用*标注