rollup打包vue2.x组件库JSX无法识别的踩坑记

4,248 阅读3分钟

打包组件库,首先想到就是用Rollup,感觉 library 打包用 Rollup,更小的打包体积、更多选择的输入文件格式,比如ES6 module, CommonJS等。

关于Rollup 和 Webpack 打包性能优化对比可参考这篇文章 Tree-Shaking性能优化实践 - 原理篇

本文主要记录的是遇到了rollup打包Vue2.x组件库的JSX无法识别的问题。Rollup的一些基础打包操作,网上都有很多非常好的讲解,可参考:rollup-完全入门指南

Rollup英文官方文档,英文的文档信息更新及时。

组件库Vue2.x需要的基础配置

  1. 组件库基础框架版本

        vue 2.6.11
        node 14.4.0
        babel 7.14.0
    
  2. 组件库的项目结构参考的是element-ui结构。

    安装rollup

        npm install --global rollup
    

组件库的开发肯定少不了引入模块、es6等,因此需要用插件(Plugins) 在打包的过程中更改Rollup的一些行为。

  1. 安装插件

    Rollup官方插件库

    由于 Node 模块使用的是 CommonJS,它并不被 Rollup 兼容因此不能直接使用。因此这两插件主要是解决该问题。

    npm i -D @rollup/plugin-node-resolve @rollup/plugin-commonjs
    

    rollup-plugin-vue插件需指定版本,@5.1.9对应的是vue2.x,@6.0.0以上对应的是vue3.x

    npm i -D rollup-plugin-vue@latest
    

    rollup 代码压缩插件

        rollup-plugin-terser
    

    rollup-plugin-babel 该插件就是踩的关键的坑了。开源库提示,rollup-plugin-babel此插件迁移到了@rollup/plugin-babel,于是更新到了@rollup/plugin-babel调试,没使用jsx语法的打包没问题,使用了jsx语法的都无法识别,改为rollup-plugin-babel后则正常了。

    rollup-plugin-babel插件需指定版本,babel7.x

        npm install --save-dev rollup-plugin-babel@latest
    

    babel6.x

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

    rollup-plugin-babel插件需要 babel 支持

        npm install --save-dev @babel/core @babel/cli @babel/preset-env 
    

    vue2.0 JSX 需要 babel-plugin-transform-vue-jsx支持

        npm install\
      babel-plugin-syntax-jsx\
      babel-plugin-transform-vue-jsx\
      babel-helper-vue-jsx-merge-props\
      babel-preset-env\
      --save-dev
    

配置文件内容如下:

  • .babelrc
    {
        "presets": [
            "@vue/app",
            [
            "@babel/preset-env",
              {
                "modules"false
              }
            ]
          ],
        "ignore": ["node_modules/**"],
        "plugins": [
            "@babel/plugin-transform-runtime",
            "@babel/plugin-syntax-dynamic-import",
            "@babel/plugin-proposal-object-rest-spread"
          ]
    }
  • rollup.config.js
    import {camelCase} from 'lodash'
    import babel from 'rollup-plugin-babel'
    //import { babel } from '@rollup/plugin-babel'
    import commonjs from '@rollup/plugin-commonjs'
    import json from '@rollup/plugin-json'

    import resolve from '@rollup/plugin-node-resolve'
    import replace from '@rollup/plugin-replace' // 打包时替换代码中的指定字符串
    import vue from 'rollup-plugin-vue'
    import postcss from 'rollup-plugin-postcss'
    import filesize from 'rollup-plugin-filesize' // 显示打包文件大小
    import {terser} from 'rollup-plugin-terser' // 代码压缩

    import pack from './package.json'

    const projectName = pack.name
    const sass = require('node-sass')
    const path = require('path')
    
    // compute globals from dependencies
    const globals =
      pack.dependencies &&
      Object.assign(
        {},
        ...Object.keys(pack.dependencies).map((key) => ({
          [key]: camelCase(key),
        }))
      )

    const builds = {
      // (CommonJS). Used by bundlers e.g. Webpack & Browserify
      cjs: {
        entry: 'src/index.js',
        dest: `dist/${projectName}.common.js`,
        format: 'cjs',
      },
      // (ES Modules). Used by bundlers that support ES Modules,
      // e.g. Rollup & Webpack 2
      esm: {
        entry: 'src/index.js',
        dest: `dist/${projectName}.esm.js`,
        format: 'es',
      },
      // build (Browser)
      'umd-dev': {
        entry: 'src/index.umd.js',
        dest: `dist/${projectName}.js`,
        format: 'umd',
        env: 'development',
      },
      // production build (Browser)
      'umd-prod': {
        entry: 'src/index.umd.js',
        dest: `dist/${projectName}.min.js`,
        format: 'umd',
        env: 'production',
      },
    }

    const processSass = function(context) {
      return new Promise((resolve, reject) => {
        sass.render(
          {
            file: context,
          },
          function(err, result) {
            if (!err) {
              resolve(result)
            } else {
              reject(err)
            }
          }
        )
      })
    }

    function genConfig(name) {
      const opts = builds[name]
      const config = {
        input: opts.entry,
        external: (id) => pack.dependencies && pack.dependencies[id], // exclude dependencies from build
        plugins: [
          vue({compileTemplate: true, css: true}),
          babel({
            runtimeHelpers: true,
            exclude: 'node_modules/**',
          }),
          resolve({
            browser: true,
            preferBuiltins: false,
            extensions: ['.js', '.json', '.jsx', '.vue'],
          }),
          commonjs(),
          json(),

          postcss({
            minimize: true,
            extensions: ['.css', '.scss'],
            process: processSass,
            extract: path.resolve(`dist/style/${projectName}.css`)
          }),

          filesize(),
        ].concat(opts.plugins || []),
        output: {
          exports: 'named',
          file: opts.dest,
          format: opts.format,
          // define globals in window from external dependencies
          globals,
          name: opts.moduleName || projectName,
        },
      }

      if (opts.env) {
        config.plugins.push(
          replace({
            'process.env.NODE_ENV': JSON.stringify(opts.env),
          })
        )

        // minify on production targets
        if (opts.env === 'production') {
          config.plugins.push(terser())
        }
      }

      Object.defineProperty(config, '_name', {
        enumerable: false,
        value: name,
      })

      return config
    }

    const target = process.env.TARGET || 'umd-prod'
    module.exports = genConfig(target)

  • 配置scripts脚本 在根目录的 package.json 中配置 build 脚本
"scripts": {
    "build-lib""npm run build:cjs && npm run build:es && npm run build:umd:dev && npm run build:umd:prod",
    "build:cjs""rollup -c --environment TARGET:cjs",
    "build:es""rollup -c --environment TARGET:esm",
    "build:umd:dev""rollup -c --environment TARGET:umd-dev",
    "build:umd:prod""rollup -c --environment TARGET:umd-prod",
    "pub""npm run build-lib && npm publish --access public"
}

存在的问题

@rollup/plugin-babel 替换 rollup-plugin-babel 待解决中,欢迎在评论区讨论。