Vue 是如何用 Rollup 打包的?

Posted 全栈修仙之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue 是如何用 Rollup 打包的?相关的知识,希望对你有一定的参考价值。

Rollup 是一个 javascript 模块打包器,它将小块的代码编译并合并成更大、更复杂的代码,比如打包一个库或应用程序。它使用的是 ES Modules 模块化标准,而不是之前的模块化方案,如 CommonJS 和 AMD。ES 模块可以让你自由、无缝地使用你最喜爱库中那些最有用的独立函数,而让你的项目无需包含其他未使用的代码。

近期在团队内组织学习 Rollup 专题,在着重介绍了 Rollup 核心概念和插件的 Hooks 机制后,为了让小伙伴们能够深入了解 Rollup 在实际项目中的应用。我们就把目光转向了优秀的开源项目,之后就选择了尤大的 Vue/Vite/Vue3 项目,接下来本文将先介绍 Rollup 在 Vue 中的应用。

项目根目录下的 package.json 文件中,我们可以找到 scripts 字段,在该字段内定义了如何构建 Vue 项目的相关脚本。

命令为例,来介绍一下与 rollup 相关的配置项:

  • -c:指定 rollup 打包的配置文件;
  • -w:开启监听模式,当文件发生变化的时候,会自动打包;
  • --environment:设置环境变量,设置后可以通过 process.env 对象来获取已配置的值。
  • dev 命令可知 rollup 的配置文件是 scripts/config.js

    有值的话,就会根据 TARGET 的值动态生成打包配置对象。

    函数内部,会从 builds 对象中获取当前目标对应的构建配置对象。当目标为 \'web-full-dev\' 时,它对应的配置对象如下所示:

    (输出文件)、format(输出格式)等信息。当获取构建配置对象后,就根据 rollup 的要求生成对应的配置对象。

    需要注意的是,在 Vue 项目的根目录中是没有 web 目录的,该项目的目录结构如下所示:

    入口文件的位置在哪呢?其实是利用了 rollup 的 @rollup/plugin-alias 插件为地址取了个别名。具体的映射规则被定义在 scripts/alias.js 文件中:

    别名对应的路径,该路径对应的文件结构如下:

    对象,相信你也知道了 Vue 是如何打包不同类型的文件,以满足不同场景的需求,比如含有编译器和不包含编译器的版本。分析完 dev 命令的处理流程,下面我来分析 build 命令。

    scripts 字段,我们可以找到 build 命令的定义:

    命令时,会使用 node 应用程序执行 scripts/build.js 文件:

    文件中,会先获取所有的构建目标,然后根据进行过滤操作,最后再调用 build 函数进行构建操作,该函数的处理逻辑也很简单,就是遍历构建列表,然后调用 buildEntry 函数执行构建操作。

    函数执行时,就会开始调用 buildEntry 函数,在该函数内部就是根据传入了配置对象调用 rollup.rollup API 进行构建操作:

    函数中是通过调用 write 函数来生成文件:

    函数内部是通过 fs.writeFile 函数来生成文件,该函数还支持 zip 参数,用于输出经过 gzip 压缩后的大小。现在我们已经分析完了 devbuild 命令,最后我们来简单介绍一下构建过程中所使用的一些核心插件。

     文件中,我们可以看到 Vue2 项目中用到的 rollup 插件:

    插件在前面我们已经知道它的作用了。而其他插件的作用如下:

  • rollup-plugin-buble:该插件使用 buble 转换 ES2015 代码,它已经被移到新的仓库 @rollup/plugin-buble;
  • rollup-plugin-commonjs:该插件用于把 CommonJS 模块转换为 ES6 Modules,它已经移到新的仓库 @rollup/plugin-commonjs;
  • rollup-plugin-flow-no-whitespace:该插件用于移除 flow types 中的空格;
  • rollup-plugin-node-resolve:该插件用于支持使用 node_modules 中第三方模块,会使用 Node 模块解析算法来定位模块。它也被移动到新的仓库 @rollup/plugin-node-resolve;
  • rollup-plugin-replace:该插件用于在打包时执行字符串替换操作,它也被移动到新的仓库 @rollup/plugin-replace。
  • 除了以上的插件,在实际的项目中,你也可以使用 Rollup 官方仓库提供的插件,来实现对应的功能,具体如下图所示(仅包含部分插件):

    (来源:https://github.com/rollup/plugins)

    总结

    本文只是简单介绍了 Rollup 在 Vue 2 中的应用,很多细节并没有展开介绍,感兴趣的小伙伴可以自行学习一下。如果遇到问题的话,欢迎跟我一起交流哈。另外,你们也可以自行分析一下在 Vue 3 和 Vite 项目中是如何利用 Rollup 进行打包的。

    vue3源码分析——rollup打包monorepo

    引言

    <<往期回顾>>

    1. 手写vue3源码——创建项目
    2. 手写vue3源码——reactive, effect ,scheduler, stop
    3. 手写vue3源码——readonly, isReactive,isReadonly, shallowReadonly
    4. 手写vue3源码——ref, computed

    本期咋们就先放一放源码,咋们如何打包monorepo应用,主要是源码看累了🤣🤣🤣,打包工具也是一门必须课,所有的源码请查看

    效果

    为了提供大家的学习兴趣,咋们先来看看效果,准备发车,请系好安全带🚗🚗🚗

    cjs 结果预览

    esm 结果预览

    声明文件预览

    正文

    vue3使用的是rollup来打包的,咋们也用rollup来打包咋们的应用,有不了解rollup的请查看官网,monorepo是多个单体仓库合并得到的,那么咋们就先来打包单个仓库,然后再来想办法怎么一键打包全部

    打包shared

    在我项目中,shared仓库是相当与utils函数的集合,用于对外导出一些工具函数,那么咋们可以在本目录下的package.json中安装rollup。 正当我就想在shared目录下面安装rollup插件的时候,我大脑给了个慢着的问号?

    monorepo 是不是可以在跟下面安装依赖,然后子包都可以共享,基于这一特征。我毫不犹豫在根目录下面敲下了下面的命令:

    pnpm add rollup -w -D
    复制代码
    

    有了rollup,咋们是不是需要在打包的目录下面来搞个配置文件rollup.config.js,里面咋们写上入口,出口,打包的格式

    // 由于咋们需要打包成cjs, ems的格式,对外导出一个函数吧
    
    [
      
        input: './src/index.ts',
        output: 
          file: 'dist/index.esm.js',
          format: 'esm',
        ,
      ,
      
        input: './src/index.ts',
        output: 
          file: 'dist/index.cjs.js',
          format: 'cjs',
        ,
      
     ]
    复制代码
    

    然后在本目录下的package.json中加入打包的命令:

     "build": "rollup -c"
    复制代码
    

    nice, 到这了就完了,咋们试一下,结果:

    分析错误可以发现,咋们是用了ts的语法,rollup无法转换ts的语法,需要使用插件了。😉😉😉

    那么rollup转换ts的插件也是有好多种,这里咋们用一个最快的那种,esbuild, rollup-plugin-esbuild

    pnpm add esbuild rollup-plugin-esbuild -w -D
    复制代码
    

    关于rollup-plugin-esbuild这个插件,官方的介绍是说:

    esbuild is by far one of the fastest TS/ESNext to ES6 compilers and minifier, this plugin replaces rollup-plugin-typescript2, @rollup/plugin-typescript and rollup-plugin-terser for you. 意思是说,这个插件是目前来说转换ts/esnext到es6是最快的编译和压缩,这个插件可以代替 rollup-plugin-typescript2, @rollup/plugin-typescript and rollup-plugin-terser的集合

    但是如果咋们需要打包非常低版本的代码,那就请查看rollup 实战第三节 打包生产打包低版本的代码.

    言归正传,那么咋们把插件用上,在配置文件上加上插件

    //... 省略其他
    plugins: [
          esbuild(
            target: 'node14',
          ),
        ]
    复制代码
    

    再来一次🤩🤩🤩

    通过结果,咋们可以看到已经打包成功了!🎉🎉🎉

    但是咋们是有ts的,肯定还需要生成咋们代码的类型吧,那就使用 rollup-plugin-dts这个来生成

    pnpm add rollup-plugin-dts -w -D
    复制代码
    

    rollup-plugin-dts详情请查看

    // 在数组后面在加上一项,
    
        input: './src/index.ts',
        output: 
          file: 'dist/index.dts',
          format: 'esm',
        ,
        plugins: [
          dts(),
        ],
      ,
    复制代码
    

    然后就可以ok啦,咋们单个项目就完成了

    打包多个

    既然单个是这么写,那么其他的咋们是不是也可以写配置文件呢?对的,没错,可以在对应的单体项目下面写上rollup.config.js来对他们进行打包的配置

    然后咋们在跟目录下面的package.json中加入一行命令:

    "build": "pnpm -r --filter=./packages/** run build"
    复制代码
    

    咋们来拆分下命令

    1. pnpm -r 等同于 pnpm --recursive,意思是说在工作区的每个项目中运行命令,不包括根项目详情查看
    2. --filter=./packages/**意思是说,过滤其他文件和文件夹,只使用packages下面的所有文件夹
    3. run build 是 pnpm -r run build的后缀,执行package.json中的build指令,详情请查看

    合起来的意思是说,依次执行packages里面所有文件夹的package.json的build命令

    优化

    通过上面的方式咋们就可以打包成功了,但是这里咋们还可以进行优化下,每一次打包dist结果都需要手动删除,咋们可以使用 rimraf 这个库来帮我们自动删除

    pnpm add rimraf -d -W
    复制代码
    

    然后在每一个子包中修改build的命令

    "build": "rimraf dist && rollup -c"
    复制代码
    

    对比vue3打包

    这里可能有的人会说,vue3仓库都不是这么玩的,的确,vue3仓库的打包流程如下:

    有兴趣的可以取看源码哈,这里给出流程图,想要使用这种方式的就自己实现哈!🎃🎃🎃

    以上是关于Vue 是如何用 Rollup 打包的?的主要内容,如果未能解决你的问题,请参考以下文章

    vue3源码分析——rollup打包monorepo

    vue3源码分析——rollup打包monorepo

    rollup打包工具

    入门React与Vue共同的选择——Rollup

    rollup 实战第三节 打包生产

    使用rollup打包和发布npm时遇到的问题