一次优化webpack打包的经历

来源:互联网 发布:linux 显卡性能测试 编辑:程序博客网 时间:2024/06/15 16:20

起因

如题,有个项目每次打包时间均有480s左右,之前忙于业务开发,无暇修复,小组成员深受其害。今天,分配了时间着手解决一下。

过程

打开收藏夹的一篇webpack优化教程,按步进行优化。
依次使用了

  • dll打包第三方npm包
  • happypack优化loader

happypack的readme更新不够及时,在找 ExtractTextPlugin 使用方法着实费了功夫
其中happypack 和 ExtractTextPlugin 抽取css共同使用的方法请参考这里

挫折

经历上步优化,打包时间稳定在了410s左右…
好像也没什么区别

转机

灵机一动,死马当活马医,将webpack打包时停滞时间最长的提示 addtional asset processing 直接googe,然后将查到的所有网页的解决方案都试一试,然后在尝试某一篇github上发现的一个优化方法时

webpack提供的UglifyJS插件由于采用单线程压缩,速度很慢 ,webpack-parallel-uglify-plugin插件可以并行运行UglifyJS插件,这可以有效减少构建时间,当然,该插件应用于生产环境而非开发环境,配置如下:var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');new ParallelUglifyPlugin({   cacheDir: '.cache/',   uglifyJS:{     output: {       comments: false     },     compress: {       warnings: false     }   } })

打包时间瞬间就降低到40s!!!!!感谢万能的谷歌!!

总结

打包配置最终如下

//--webpack.config.js// 一些通用的库var webpack = require('webpack');var path = require('path');var url = require('url');var webpackHotDevServer = require('webpack-dev-server');// 用到的插件var ExtractTextPlugin = require('extract-text-webpack-plugin');var HtmlWebpackPlugin = require('html-webpack-plugin');var WebpackBrowserPlugin = require('webpack-browser-plugin');var HappyPack = require('happypack');//多线程loader 加快编译速度var os = require('os');var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');// 编译输出的控制台信息美化插件var DashboardPlugin = require('webpack-dashboard/plugin');// 获取 node_modules 文件夹的路径var node_modules = path.resolve(__dirname, 'node_modules');// 使用压缩后的 ReactJS, 优化编译速度var pathToReact = path.resolve(node_modules, 'react/dist/react.min.js');var pathMapboxgl = path.resolve(__dirname, 'src/libs/mapbox-gl/mapbox-gl-dev.js');module.exports = {    // 调试模式    // debug: true,    // 设置webpack识别的base目录, 绝对路径    context: path.resolve(__dirname, './src/'),    performance: {        hints: "warning"    },    cache: true,    devtool: 'hidden-source-map',    devServer: {        // 设置热启动服务器的根目录,不然一些图片等静态资源是加不到的哦        // contentBase: path.join(__dirname, './src/'),        contentBase: false,        hot: true,        inline: true,        port: 3002,        quiet: true,        noInfo: true,        clientLogLevel: 'error',        stats: "errors-only",        // lazy: true,        // filename: "vendors.js"    },    // 定义的实体    entry: {        'index': ['./app.jsx'],        'vendors': ['whatwg-fetch']    },    output: {        // 这个是项目的输出路径,必须是绝对路径        path: path.resolve(__dirname, "dist"),        // path: path.resolve(__dirname, ""),        filename: 'js/[name].js?v=[hash:5]',        // 添加 chunkFilename 为了实现 react-router的懒加载        chunkFilename: 'js/[name].chunk.js?v=[chunkhash:5]',        // 编译后的包的访问位置        publicPath: './'    },    resolve: {        // root: path.resolve(__dirname, 'app'),        alias: {            'mapboxgl': pathMapboxgl,            'reactmin': pathToReact        },        extensions: ['.js', '.sass', '.jsx', '.jpg', '.jpeg', '.gif', '.png']    },    module: {        noParse: [            /mapbox-gl.+\.js$/,        ],        rules: [            {                test: /\.jsx$/,                exclude: /(node_modules)/,                use:'happypack/loader?id=jsx'            }, {                test: /\.js$/,                exclude: /(node_modules[^\/gago\-.*]|bower_components|libs\/mapbox-gl)/,                // loaders: ['babel-loader?cacheDirectory&presets[]=es2015,presets[]=react,presets[]=stage-0']                use: 'happypack/loader?id=js'            },{                test: /\.scss$/,                use: ExtractTextPlugin.extract({                    fallback: ['style-loader'],                    loader: 'happypack/loader?id=scss',                    publicPath:'../'                })            }, {                test: /\.(jpg|jpeg|gif|png)$/,                loader: 'url-loader?limit=8192&name=./images/[name].[ext]'            }, {                test: /\.css$/,                use: ExtractTextPlugin.extract({                    fallback: ['style-loader'],                    // use: ['css-loader', 'postcss-loader'],                    use: 'happypack/loader?id=css',                    publicPath:'../'                                    })            }, {                test: /\.(woff|woff2|eot|ttf|svg)(\?v=\d+\.\d+\.\d+)?$/,                loader: 'url-loader?limit=10000&mimetype=application/font-woff&name=./fonts/[name].[ext]'            }        ]    },    plugins: [        new webpack.DllReferencePlugin({            context: __dirname,            /**             * 在这里引入 manifest 文件             */            manifest: require('./dist/vendors-manifest.json')        }),        //  new WebpackBrowserPlugin(),        new HappyPack({            id: 'jsx',            // threads: 4,            threadPool: happyThreadPool,            loaders: [{                loader: 'babel-loader',                options: {                    presets: ['react', 'es2015', 'stage-0'],                    plugins: [                        ['import', { libraryName: 'antd', style: 'css', }]                    ]                }            }]        }),        new HappyPack({            id: 'js',            // threads: 4,            threadPool: happyThreadPool,            loaders: [{                loader: 'babel-loader',                options: {                    presets: [ 'es2015','react', 'stage-0'],                    cacheDirectory: true                }            }]        }),        new HappyPack({            id: 'scss',            // threads: 4,            threadPool: happyThreadPool,            loaders: ['css-loader', 'sass-loader']        }),        new HappyPack({            id: 'css',            // threads: 4,            threadPool: happyThreadPool,            loaders: ['css-loader', 'postcss-loader'],        }),        // 控制台输出美化        new DashboardPlugin(),        new webpack.optimize.CommonsChunkPlugin({            // 模块的名字--在entry里面定义的            name: 'vendors',            // 模块的输出文件名            filename: 'js/vendors.js'        }),        new webpack.HotModuleReplacementPlugin(),        // 混淆代码        // new webpack.optimize.UglifyJsPlugin({        //     compress: {        //         warnings: false        //     },        //     sourceMap: false        // }),        new ParallelUglifyPlugin({            cacheDir: '.cache/',            uglifyJS:{                output: {                    comments: false                },                compress: {                    warnings: false                }            }        }),        // 使用 ProvidePlugin 加载使用率高的依赖库        new webpack.ProvidePlugin({            React: 'reactmin',            mapboxgl: 'mapboxgl',            jQuery: 'jquery',            'window.jQuery': 'jquery',            $: 'jquery',        }),        new ExtractTextPlugin({            filename: 'css/[name].css?v=[chunkhash:5]',            allChunks: false,            // disable: true        }),        new HtmlWebpackPlugin({            filename: 'index.html',            template: 'index.html',            chunks: ['index', 'vendors']        }),        // 这是用于判断当前的环境(开发环境还是生产环境)        new webpack.DefinePlugin({            PRODUCTION: JSON.stringify(false),            'process.env': {                'NODE_ENV': JSON.stringify('production')            }        })    ]};
//--webpack.dll.config.jsconst {join} = require('path');const webpack = require('webpack');const node_modules = join(__dirname, 'node_modules');// 使用压缩后的 ReactJS, 优化编译速度const pathToReact = join(node_modules, 'react/dist/react.min.js');const pathMapboxgl = join(__dirname, 'src/libs/mapbox-gl/mapbox-gl-dev.js');const OutputDir = join(__dirname,'dist');module.exports = {    entry: {        vendors: ['mapboxgl','react', 'react-dom','react-router','echarts','jquery','lodash','material-ui']    },    output: {        path: OutputDir,        filename: 'js/[name].dll.js',    /**     * output.library     * 将会定义为 window.${output.library}     * 在这次的例子中,将会定义为`window.vendor_library`     */        library: '[name]_library'    },    resolve: {        alias: {            'mapboxgl': pathMapboxgl,        },        // extensions: ['.js', '.sass', '.jsx', '.jpg', '.jpeg', '.gif', '.png']    },    plugins: [        new webpack.DllPlugin({      /**       * path       * 定义 manifest 文件生成的位置       * [name]的部分由entry的名字替换       */            path: join(OutputDir, '[name]-manifest.json'),      /**       * name       * dll bundle 输出到那个全局变量上       * 和 output.library 一样即可。        */            name: '[name]_library'        })    ]};
0 0
原创粉丝点击