vue项目的webpack构建优化

值得一提的是,在说webpack的速度优化之前,按需加载和按需引入,是你先要做好的,之后再说速度优化的问题。

按需加载,参考:https://segmentfault.com/a/1190000011519350

对参考博客中的一些问题的补充,

当前router.js中代码为

const Index = () => import('@/components/Index')时,

路由比较多,一个个修改太费劲,这个时候可以试一下,sublime有个很强大的功能,可以根据正则替换匹配的代码。

^const\s+(\w+)\s+.*@(.*)'\)

const $1 = () => import(/* webpackChunkName: "$1" */ '@$2')

还有一个有趣的功能,正常情况下你npm run build 编译好的js是这样的:

在本地测试的时候,我想知道js具体对应那些模块,调试的时候会更得心应手,这个时候,只需要改一下 .babelrc webpack.prod.conf.js这两个文件。

.babelrc中,

{

     "presets": [

            ["env", { "modules": false }],

            "stage-2"

     ],

     "plugins": ["transform-runtime"],

     "comments": false, // 此项设置为true

      "env": {

          "test": {

               "presets": ["env", "stage-2"],

                "plugins": [ "istanbul" ]

           }

       }

}

webpack.prod.conf.js

output: {

      path: config.build.assetsRoot,

      filename: utils.assetsPath('js/[name].[chunkhash].js'),

      chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')

},

修改为

output: {

     path: config.build.assetsRoot,

     filename: utils.assetsPath('js/[name].[chunkhash].js'),

     chunkFilename: utils.assetsPath('js/[name].js')

},

修改这两项之后,重新npm run build编译,js则会显示为

js文件的名称是对应模块的名称。

 

一.  webpack-parallel-uglify-plugin插件

1. webpack提供的UglifyJS插件由于采用单线程压缩,速度很慢 , webpack-parallel-uglify-plugin插件可以并行运行UglifyJS插件,这可以有效减少构建时间。

2. 修改webpack.prod.conf.js文件

var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')// 删掉webpack提供的UglifyJS插件

// new webpack.optimize.UglifyJsPlugin({

   // compress: {

     // warnings: false

   // },

   // output: {

     // comments: false,

   // },

   // sourceMap: true

// }),

// 增加 webpack-parallel-uglify-plugin来替换

new ParallelUglifyPlugin({ cacheDir: '.cache/', uglifyJS:{ output: { comments: false }, compress: { warnings: false } }})

二. 换用happypack多进程构建

webpack的构建毕竟还是单进程的。采用happypack可以改为多进程构建。而对于小文件而言,happypack效果并不明显。而对于babel-loader编译的庞大的js文件群来说,则是一大利器。

首先安装:npm install happypack --save-dev或者yarn add happypack

然后修改webpack.base.conf.js的配置如下:

module.exports = {

  plugins: [

    new HappyPack({

      id: 'js',

      cache: true,

      loaders: ['babel-loader?cacheDirectory=true'],

      threadPool: happThreadPool

    })

  ],

... // 其他配置

module: {

... // 其他配置

  rules: [

    {

       test: /\.vue$/,

       loader: 'vue-loader',

       options: {

         loaders: {

           js: 'happypack/loader?id=js' // 将loader换成happypack

         }

       }

    },

    {

       test: /\.js$/,

       loader: ['happypack/loader?id=js'], // 将loader换成happypack

       include: [resolve('src'), resolve('node_modules/jsdom')], // src是项目开发的目录

    }
  
  ]

 }

}

三. webpack 3.x webpack3新特性一览  https://juejin.im/entry/5971483951882552681c4a30

1. webpack 3.x 提供了一个新的功能:Scope Hoisting,又译作“作用域提升”。只需在配置文件中添加一个新的插件,就可以让 Webpack 打包出来的代码文件更小、运行的更快。

注意:使用这个方法的前提是webpack版本必须是3.x

2. 修改webpack.prod.conf.js

......plugins: [ // 往plugins添加一个配置 // ps 只针对es6的模块化有效 new webpack.optimize.ModuleConcatenationPlugin(),]

再次需要注意的地方,升级webpack,需要把一些附属插件也升级到相对应的版本

四.DllPlugin和DllReferencePlugin

对于文件大小有很高要求的话,不推荐用dll,但dll对于速度的提升还是很明显的。

Dll打包以后是独立存在的,只要其包含的库没有增减、升级,hash也不会变化,因此线上的dll代码不需要随着版本发布频繁更新。使用Dll打包的基本上都是独立库文件,这类文件有一个特性就是变化不大。只要包含的库没有升级, 增减,就不需要重新打包。这样也提高了构建速度。而且也具有可移植性,如果其他项目需要相同的库,可以直接copy过去。

1.在build文件夹下新建webpack.dll.conf.js文件

var path = require('path')

var webpack = require('webpack')

var AssetsPlugin = require('assets-webpack-plugin')

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

var config = require('../config')

var ExtractTextPlugin = require('extract-text-webpack-plugin')

var env = config.build.env



module.exports = {

    entry: {

        libs: [

            'vue/dist/vue.esm.js',

            'vue-router',

            'vuex',

            'iview',

            "fabric",

            "echarts",

            "moment",

            "numeral",

            "lodash"

        ],

    },

    output: {

        path: path.resolve(__dirname, '../libs'),

        filename: '[name].[chunkhash:7].js',

        library: '[name]_library',

    },

    plugins: [

        new webpack.DefinePlugin({
    
            'process.env': env,

        }),

        new webpack.DllPlugin({

            path: path.resolve(__dirname, '../libs/[name]-mainfest.json'),

            name: '[name]_library',

            context: __dirname, // 执行的上下文环境,对之后DllReferencePlugin有用

        }),

        new ExtractTextPlugin('[name].[contenthash:7].css'),

        new webpack.optimize.UglifyJsPlugin({

            compress: {

                warnings: false,

            },

        }),

        new AssetsPlugin({

            filename: 'bundle-config.json',

            path: './libs',

        }),

        new CleanWebpackPlugin(['libs'], {

            root: path.join(__dirname, '../'), // 绝对路径

            verbose: true,

            dry: false,
    
        }),

    ],

    module: {
    
        rules: [

            {

                test: /\.js$/,

                loader: 'babel-loader',

            },

        ],

    },

}

2.在build文件夹下新建build-dll.js文件

var path = require("path")

var webpack = require("webpack")

var dllConfig = require("./webpack.dll.conf")

var chalk = require("chalk")

var rm = require("rimraf")

var ora = require("ora")



var spinner = ora({

    color: "green",

    text: "building for Dll..."

})

spinner.start()

rm(path.resolve(__dirname, "../libs"), err => {

    if (err) throw err

    webpack(dllConfig, function(err, stats) {

        spinner.stop()

        if (err) throw err

        process.stdout.write(

            stats.toString({

                colors: true,

                modules: false,

                children: false,

                chunks: false,

                chunkModules: false

            }) + "\n\n"

        )

        console.log(chalk.cyan(" build dll succeed !.\n"))

    })

})

3.修改webpack.prod.conf.js文件(忽略其他配置)

var path = require('path')

var utils = require('./utils')

var webpack = require('webpack')

var config = require('../config')

var merge = require('webpack-merge')

var baseWebpackConfig = require('./webpack.base.conf')

var CopyWebpackPlugin = require('copy-webpack-plugin')

var HtmlWebpackPlugin = require('html-webpack-plugin')

var ExtractTextPlugin = require('extract-text-webpack-plugin')

var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

var bundleConfig = require("../libs/bundle-config.json")



plugins: [

    // 增加DllReferencePlugin配置

    // new webpack.DllReferencePlugin({

        // context: __dirname,

        // manifest: require("../libs/libs-mainfest.json") // 指向生成的manifest.json

    // }),

    new HtmlWebpackPlugin({

        // 增加两个变量

        // libJsName: bundleConfig.libs.js,

        // libCssName: bundleConfig.libs.css,

    },

    }),

    // split vendor js into its own file

    new webpack.optimize.CommonsChunkPlugin({

        name: 'vendor',

        minChunks: function (module, count) {

            // any required modules inside node_modules are extracted to vendor

            return (

                module.resource &&

                /\.js$/.test(module.resource) &&

                module.resource.indexOf(

                    path.join(__dirname, '../node_modules')

               ) === 0

            )

        }

    }),

    // copy custom static assets

    new CopyWebpackPlugin([

        // 添加

        // {

            // from: path.resolve(__dirname, "../libs"),

            // to: config.build.assetsSubDirectory,

            // ignore: ["*.json"]

        // }

    ])

]

})

4.修改模版文件index.html

<!DOCTYPE html>

<html>

    <head>

        <meta charset="utf-8">

        <meta http-equiv="X-UA-Compatible" content="IE=edge"/>

        <% if (htmlWebpackPlugin.options.libCssName){ %>

        <link rel="stylesheet" href="./static/<%=htmlWebpackPlugin.options.libCssName %>"><% } %>

        <title>善贾</title>

        <% if (htmlWebpackPlugin.options.libJsName){ %>

        <script src="./static/<%= htmlWebpackPlugin.options.libJsName %>"></script>

        <% } %>

    </head>

    <body>

        <div id="app"></div>

        <!-- built files will be auto injected -->

    </body>

</html>

5.修改package.json,增加scripts

"scripts": {

    // 添加

    "build:dll": "node build/build-dll.js"

}

6.执行,先执行npm run build:dll ,之后在执行npm run build

五.HardSourceWebpackPlugin(模块缓存)rebuild +++

这也算是webpack中的一个神器,官方给出的编译速度提升率大概在70%,但实际效果远远高于此,

1.修改webpack.prod.conf.js文件(忽略其他配置)

var HardSourceWebpackPlugin = require('hard-source-webpack-plugin')

plugins: [

    // 添加

    new HardSourceWebpackPlugin({

        // Either an absolute path or relative to webpack's options.context.

        cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',

        // Either an absolute path or relative to webpack's options.context.

        // Sets webpack's recordsPath if not already set.

        recordsPath: 'node_modules/.cache/hard-source/[confighash]/records.json',

        // Either a string of object hash function given a webpack config.

        configHash: function(webpackConfig) {

            // node-object-hash on npm can be used to build this.

            return require('node-object-hash')({sort: false}).hash(webpackConfig);

        },

        // Either false, a string, an object, or a project hashing function.

        environmentHash: {

            root: process.cwd(),

            directories: [],

            files: ['package-lock.json', 'yarn.lock'],

        }

    })

]

六.css-loader的版本 (build++,rebuild++)

css-loader是webpack中对css模块的处理。

降低css-loader的版本,虽然简单,但是对于速度的提升确是很多的。

对于css-loader来说,版本超过0.15.*,编译的速度会慢很多,所以一般推荐0.14.*,不要超过0.15.*,速度会提升50%左右,具体速度提升,看项目代码情况。

七.cache(缓存)

当代码不曾改变时,webpack会优先从缓存中读取所需数据,若查询不到相关数据,才会再次编译。

1.webpack的cache默认为false,在webpack.base.conf.js

module.exports = {

    cache: true

    // 其他配置

}

2.设置 babel 的 cacheDirectory 为true,在webpack.base.conf.js

module: {

    exprContextCritical: false,

    rules: [

    ... // 其他配置



        {

            test: /\.js$/,

            loader: 'babel-loader?cacheDirectory=true',

            include: [resolve('src'), resolve('test')]

        }

    ]

}

八.happypack

相对于node的单线程执行,无疑,多线程并行执行,速度会有所提升,而happypack就是webpack中的一个插件,目的是通过多进程模型,来加速代码构建。

1.在webpack.base.conf.js

// 添加


var os = require('os')

var HappyPack = require('happypack')

// 根据电脑的cpu判断线程数

var happThreadPool = HappyPack.ThreadPool({size: os.cpus().length})

module.exports = {

    plugins: [

        // 线程池初始化

        new HappyPack({

            id: 'js',

            cache: true,

            loaders: ['babel-loader?cacheDirectory=true'],

            threadPool: happThreadPool

        })

    ],
}

// 修改

{

    test: /\.vue$/,

    loader: 'vue-loader',

    options: vueLoaderConfig

},

{

    test: /\.js$/,

    loader: 'babel-loader',

    include: [resolve('src'), resolve('test'), resolve('node_modules/jsdom')]

}

// 为

{

    test: /\.vue$/,

    loader: 'vue-loader',

    options: {

        loaders: {

            js: 'happypack/loader?id=js' // 将loader换成happypack

        }

    }

},

{

    test: /\.js$/,

    loader: ['happypack/loader?id=js'], // 将loader换成happypack

    include: [resolve('src'), resolve('node_modules/jsdom')], // src是项目开发的目录

},

九.使用resolve=> alias

在webpack.base.conf.js中

resolve: {

    extensions: ['.js', '.vue', '.json'],

    alias: {

        'vue$': 'vue/dist/vue.esm.js',

        '@': resolve('src'),

        'assets': path.resolve(__dirname, '../src/assets')

    }

}

在alias中尽量使用别名,

resolve: { alias: { jquery: "./scripts/jquery.min.js"}}

在模块中使用 。 import 。jquery from 'jquery',这样也是可以缩短编译时间,

而且要善于利用alias中定义的别名,尽量使用这些别名,

例如:@

import Utils from '@/tool/Utils'

这些别名的使用,对于编译时间是有所缩短的。

既然说到这了,在这里也提一下,在css中使用@别名的方法。

当在css中直接使用定义的别名时,会报错,

原因是 css 文件会被用 css-loader 处理,这里 css @import 后的字符串会被 css-loader 视为绝对路径解析,因为我们并没有添加 css-loader 的 alias,所以会报找不到 @ 目录。

解决方式:(引用这种加~的路径时,必须使用了css预处理器。例如sass,less等,是否可用,并未实测)

在 Webpack 中 css import 使用 alias 相对路径的解决办法有两种(推荐第二种方法)

一是直接为 css-loader 添加 ailas 的路径,但是在 vue-webpack 给的模板中,单独针对这个插件添加配置就显得麻烦冗余了;

二是在引用路径的字符串最前面添加上 ~ 符号,如 @import "~@/style/theme";Webpack 会将以 ~ 符号作为前缀的路径视作依赖模块而去解析,这样 @ 的 alias 配置就能生效了。

具体参考:https://wiki.zthxxx.me/wiki/%E6%8A%80%E6%9C%AF%E5%BC%80%E5%8F%91/%E5%89%8D%E7%AB%AF/Webpack-%E4%B8%AD-css-import-%E4%BD%BF%E7%94%A8-alias-%E7%9B%B8%E5%AF%B9%E8%B7%AF%E5%BE%84/

以上是我在项目中遇到的一些问题,通过参考一些博客,和在项目中的测试,总结出来的一些方法。

 

 

 

 

Logo

前往低代码交流专区

更多推荐