citrus327/issue-blog-record

使用rollup构建library的一次尝试

Closed this issue · 0 comments

使用rollup构建library的一次尝试

因为在设计博客和CMS的时候,有一个设想就是在CMS里去编辑md,同时实时预览,这个预览和实际提交在博客上展示要求完全一致。所以就想着自己弄一个预览模块,在两个项目之前共享代码。这就涉及到一个Markdown Preview的工具。这个工具其实就是从MD => HTML,使用highlight.js做代码高亮,一些自定义的配置和样式文件,然后打包成一个js包。

这个打包环节其实是想用webpack打一个umd的包就得了,但是一直知道有个rollup的工具存在,非常轻量,同时Vue.js也是通过rollup打包的,所以就想做出一次尝试。以下是阅读文档,结合awesome rollup仓库总结的一些经验。

同时本文只会涉及到一些rollup相关的,关于markdown处理会再开一篇文章记录。

起步

rollup github地址

官方文档

官方提供的构建library的模板

awesome-rollup

本文涉及到的源码

package.json

{
  "name": "my-package",
  "version": "0.1.0",
  "main": "dist/my-package.js"
}

通常,包内的package.json通常用有一个叫main的属性,他说明的是本包的内容是在dist/my-package.js中。

像Webpack, Browserify之类的bundler会解析这个main, 然后引入main属性对应的js,同时根据dependencies去载入相应依赖。
在第三方打包时一般都会优先选用umd的包,因为这样浏览器也可以使用,所以一般第三方的lib的main属性通常都是umd的包。

而rollup属于ES2015-aware的工具,在rollup内使用CJS或者UMD并不是最理想的情况,因为无法使用ES6 module的特性。
如果对方在使用rollup作为他的bundler, 而也说了rollup属于ES2015-aware的工具,他会优先读取package.json里的module属性,如果没有,才会读main属性,这样既可以保证一般bundler可以正常解析文件,同时在使用rollup的时候会优先读取module里的es包。

所以package.json就会变成:

{
  "name": "my-package",
  "version": "0.1.0",
  "main": "dist/my-package.umd.js",
  "module": "dist/my-package.esm.js"
}

这对于打出的包来说属于双赢。
具体可以查看官方对于这种做法的解释

配置文件

配置文件详细文档

rollup的配置文件可以使用es6语法编写
使用-c来指定config文件,默认读取根目录下rollup.config.js

  rollup -c
  rollup --config
  rollup -c build/rollup.config.js

这里也放出我用的配置文件

import resolve from '@rollup/plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import pkg from './package.json'
import dev from 'rollup-plugin-dev'
import postcss from 'rollup-plugin-postcss'
import { string } from "rollup-plugin-string"
import { terser } from 'rollup-plugin-terser'

const devServerConfig = {
  port: 3000
}

const plugins = function (format) {
  const commonPlugins = [
    dev(devServerConfig),
    postcss({
      extract: false
    }),
    string({
      include: "**/*.md",
    }),
    terser()
  ]
  if (format === 'umd') {
    return [
      ...commonPlugins,
      resolve(),
      commonjs(),
    ]
  } else {
    return commonPlugins
  }
}

export default [
  // for browser
  {
    input: 'src/index.js',
    output: {
      name: 'MarkdownPreview',
      file: pkg.browser,
      format: 'umd'
    },
    plugins: plugins('umd')
  },

  // for cjs and esm
  {
    input: 'src/index.js',
    external: Object.keys(pkg.dependencies),
    output: [
      {file: pkg.main, format: 'cjs'},
      {file: pkg.module, format: 'es'},
    ],
    plugins: plugins()
  }
]

常用依赖

  1. rollup-plugin-commonjs
    支持解析commonjs包至es6 module
  2. @rollup/plugin-node-resolve
    支持解析node_modules里的包 之前的包rollup-plugin-node-resolve已经archive了且不再维护
  3. rollup-plugin-vue
  4. rollup-plugin-jsx
  5. rollup-plugin-md
  6. rollup-plugin-terser
  7. rollup-plugin-string

  1. rollup-plugin-uglify
    因为之前没有用过terser作为minify的工具,所以选择了rollup-plugin-uglify
    打包esm的时候竟然不支持es6语法。terser官方也说了这个问题,

Why choose terser?
uglify-es is no longer maintained and uglify-js does not support ES6+.
terser is a fork of uglify-es that mostly retains API and CLI compatibility with uglify-es and uglify-js@3.

所以使用rollup-plugin-terser作为minify工具。