5

这段时间在对公司的打包构建速度和app.js文件大小进行优化。使用到了webpack的DllPlugin和DllReferencePlugin。今天就来简单讲讲它们的使用。

其实对于这两个插件网上已经有很多各种各样的文章了。不过笔者认为,那些文章都写得很棒,但是对于部分需要注意的地方都没有说明。这里笔者就根据自己的理解讲讲个人的理解。如果有什么不对的地方希望能有人指出,小弟在此先谢过了。

DllPlugin

首先我们来讲讲DLLPlugin这个插件吧。这个插件的作用是创建dll文件和manifest文件。dll文件就是就是我们需要引入的文件,manifest文件是引导webpack引入到当前项目的文件。好吧,直接贴代码:

webpack.dll.conf.js

var path = require('path')

var webpack = require('webpack')
var CleanWebpackPlugin = require('clean-webpack-plugin')

var config = require('../config')
var __root = xxx // 这里是你的根路径
// 这里是静态资源路径,如果使用vue-cli的,就是根目录下的static目录;
// 如果使用@vue/cli的就是根目录下的public目录。使用其他的脚手架需要根据具体情况考虑。
var static = xxx 

module.exports = {
    context: __root, // 这里配置的context就是后面dll的context
    entry: {
        'core': ['vue', 'vue-router', 'vuex'],
        'asset': ['axios', 'fastclick']
    },
    output: {
        path: path.resolve(static, 'lib'),
        filename: '[name]-[chunkhash:7].dll.js',
        library: 'lib_[name]',
        // *** 这里不要添加libraryTarget,否则webpack打包时会出错。
        // (提示是__WEBPACK__EXTERNAL__MODULE__xxx未定义) ***
        // libraryTarget: 'umd'
    },
    resolve: {
        modules: [path.resolve(__root, 'node_modules')],
        extensions: ['.js', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    },
    // 这里没有写loaders,如果有需要可以自行添加loaders
    plugins: [
        // *** 这里很关键 ***
        new webpack.DllPlugin({ // 因为上面写了context,所以这里可以不指定context
            // 这里manifest的名字必须要有变量,因为类似上面的core和asset会分别创建一个manifest,
            // 如果名称相同,manifest会生成不规范的json,在引用时会报错。
            path: path.resolve(__root, 'static/manifest/[name].manifest.json'),
            name: 'lib_[name]' // *** 这里的名字必须与output.library一致 ***
        }),
        // 这个是用来稳定hash值,防止出现webpack的hash出现莫名的变化
        new webpack.HashedModuleIdsPlugin(),
        new webpack.NamedChunksPlugin()
        ... 其他插件
    ]
}

上面就是webpack.dll.conf.js的主要配置。执行之后会在static文件夹(在vue-cli生成的项目中用于存放不需要webpack构建的静态文件【@vue/cli中的目录名为Public】)下生成两个文件夹(lib文件夹和mainfest文件夹)。其中lib下的文件为我们已经打包好的组件库,mainfest下的文件在引入项目时有用(是一个JSON文件)。

DllReferencePlugin

webpack.conf.js

var path = require('path')

// 获取dll文件的manifest
function getDllManifest () {
    var plugins = []
    Object.keys({
        'core': ['vue', 'vue-router', 'vuex'],
        'asset': ['axios', 'fastclick']
    }).forEach((name) => {
        plugins.push(
            new webpack.DllReferencePlugin({
                context: __root, // 这里的context必须与DllPlugin中的context保持一致
                manifest: path.resolve(__root, 'static/manifest/[name].manifest.json').replace(/\[name\]/gi, name)
            })
        )
    })
    return plugins
}

module.exports = {
    entry: {
        app: './src/main.js'
    },
    output: {
        path: path.resolve(__dirname, '..')
        filename: 'js/[name]js'
    },
    ... 其他代码
    plugins: [
        // *** 所以这里可能会引入多个DllReferencePlugin,具体要看有几个manifest文件了。***
        ...getDllManifest(),
        new HtmlWebpackPlugin({
            filename: utils.assetsPath('page/retail.html'),
            template: path.join(config.dev.page, 'retail.html'),
            inject: true,
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeAttributeQuotes: true
                // more options:
                // https://github.com/kangax/html-minifier#options-quick-reference
            },
            // necessary to consistently work with multiple chunks via CommonsChunkPlugin
            chunksSortMode: 'dependency'
        }),

        // dll文件需要插件将其引入到html文件中,以方便后续使用
        new HTMLWebpackIncludeAssetsPlugin({
            append: false,
            publicPath: config.build.assetsPublicPath,
            assets: [{
                path: config.build.assetsSubDirectory,
                glob: '**/*.js',
                globPath: config.dll.static
            }],
        }),

        // 将dll文件拷贝到你的dist目录下
        new CopyWebpackPlugin([
            {
                // 这里是dll文件当前所在的文件目录
                from: static,
                // 这里是生产环境的资源地址
                to: config.build.assetsSubDirectory,
                // 过滤static中的部分文件
                ignore: ['.*', 'manifest/*']
            }
        ])
    ]
}

getDllManifest方法是将打包好的库引入到项目中(就是在html中生成script标签的方式引入,它会在app.js之前生成,保证代码执行顺序的正确性),并保证构建工具不会再次对它进行打包。以上就是生成和引用dll文件的配置。

注:

  1. output.library必须与DllPlugin配置中的name字段保持统一。
  2. 不要使用libraryTarget,否则在运行时会报__WEBPACK__EXTERNAL__MODULE__xxx is not defined错误。
  3. DllPlugincontextDllReferencePlugincontext要保持一致。
  4. manifest的名字最好是可配置的,这样方便生成多个dll文件。
  5. 如果有多个dll文件,需要添加多个DllReferencePlugin插件去分别处理。

推荐

讲webpack构建优化的


小白
30 声望2 粉丝

« 上一篇
isNaN的理解