如何用Webpack打包组件库

2,974 阅读1分钟

一个组件,从业务代码抽取。是webpack项目,怎么输出成组件库呢?

要求

  • 组件就是业务里提取的代码,希望开发环境完全一致,就用webpack。
  • 希望生成npm组件.
  • 希望能按需引入,像require('lodash/debounce')那样.

方案

多entry打包

entry: {
   input: './src/comp/input/'
   select: './src/comp/select'
   ...
   index: './src/index' // index import了所有组件
}
  output: {
        path: path.resolve(process.cwd(), 'lib'),
        filename: '[name]/index.js',
        library: 'my-ui',
        libraryTarget: 'umd',
 },

配置external,不打包这些文件

  externals: {
    vue: 'vue',
    lodash: 'lodash',
    classnames: 'classnames',
    'moment': 'moment'
 },

配置splitChunks拆成很多小文件

  plugins: [
        new MiniCssExtractPlugin({
            filename: 'index.css',
            ignoreOrder: true,
        }),
 ]
 ...
 optimization: {
        minimize: false,
        namedChunks: true,
        runtimeChunk: true,
        splitChunks: {
            chunks: 'all',
            maxInitialRequests: Infinity,
            maxAsyncRequests: Infinity,
            enforceSizeThreshold: Infinity,
            minSize: 0,
            hidePathInfo: false,
            cacheGroups: {
                styles: { // styles打包成了一个文件
                    test: (module, chunks) => module.constructor.name === 'CssModule',
                    name: "styles",
                    chunks: "all",
                    enforce: true
                },
            }
        },
    },

增加plugins,记录并生成entry文件

  {
            apply: (compiler) => {
                compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
                    const css1 = fs.readFileSync(path.resolve(__dirname, '../lib/styles.index.css'));
                    fs.unlinkSync(path.resolve(__dirname, '../lib/index.js'));

                    if (!fs.existsSync(path.resolve(__dirname, '../entry'))) {
                        fs.mkdirSync(path.resolve(__dirname, '../entry'))
                    }

                    for (let [entryName, entry] of compilation.entrypoints) {
                        let chunkStr = ''
                        entry.chunks.forEach((chunk, i) => {
                            if (i == entry.chunks.length - 1) {
                                return
                            }

                            chunkStr += `require('../lib/${chunk.id}/index')\n`;
                        })

                        const outTemplate = `
${chunkStr}
var mod = require('../lib/${entryName}')
module.exports.__esModule = mod.__esModule;
module.exports = mod;
                    `
                        fs.writeFileSync(path.resolve(__dirname, `../entry/${entryName}.js`), outTemplate)
                    }
                    return true;
                });
            }
        }

总结:

通过上面的方法,会生成 lib 和 entry文件夹

lib文件夹是webpack产出默认内容
按需引入代码使用require('mod/entry/input')
全量引入使用require('mod/entry/index')


entry文件夹作为入口,按需引入各种小包

entry的一个例子