vue首屏加载慢解决方案

2,566 阅读1分钟

一、优先使用CDN

二、动态导入

1、两种方式:

// 有两种方式供我们实现动态导入
1.import()   //ES的提案,返回以一个promise,导入的模块在then中拿到
2.require.ensure()  //webpack在编译时会静态地解析代码中的require.ensure(),将里面require的模块添加到一个分开的chunk中。这个新chunk会被webpack通过jsonp来按需加载。

2、import()实现:

image.png

npm install babel-plugin-syntax-dynamic-import --save-dev
// .babelrc
{
    "presets": [
        ...
    ],
    "plugins": ["syntax-dynamic-import"]
}
// webpack.config.js:
module.exports = {
    mode: 'production',
    entry: {
        index: path.resolve(root_path, 'index.js'),
    },
    output: {
        filename: '[name].bundle.js',
        // chunkFilename:指定非entry chunk的文件名,比如import()引入的模块不打包进entry中,而会作为单独的chunk打包,其文件名就由该属性决定
        chunkFilename: 'MaterialsCenter/js/[name].min.js',
        path: path.resolve(root_path, 'dist')
    },
    module: {
        rules: []
    }
}

index.js:点击按钮才异步加载lodash

// index.js
let btn = document.getElementById('btn');

btn.addEventListener('click', () => {
    import(
    /* webpackChunkName: "lodash" */
    /* webpackMode: "lazy" */
    'lodash').then(
        _ => {
            var app = document.getElementById('app');
            app.textContent = _.join(['Index', 'Module', 'Loaded!'], ' ');
        }
    ).catch(
        err => {
            console.log('loading module error occur', err);
        }
    )
});

3、魔法注释 还有一些其他项,如:

import(
  /* webpackInclude: /\.json$/ */
  /* webpackExclude: /\.noimport\.json$/ */
  /* webpackChunkName: "my-chunk-name" */
  /* webpackMode: "lazy" */
  /* webpackPrefetch: true */
  /* webpackPreload: true */
  `./locale/${language}`
);

三、webpack打包压缩处理

1、先使用webpack-bundle-analyzer插件查看包体大小

npm install --save-dev webpack-bundle-analyzer
// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
 plugins: [
  new BundleAnalyzerPlugin()
}

2、HtmlWebpackPlugin - 将JS文件放在body的最后

默认情况下,build后的index.html中,js的引入是在head中。

使用html-webpack-plugin插件,将inject的值改成body。就可以将js引入放到body最后。

npm install --save-dev html-webpack-plugin

3、TerserJSPlugin - 处理 js 的压缩和混淆

npm install terser-webpack-plugin --save-dev
const TerserJSPlugin = require('terser-webpack-plugin');

optimization: {
    minimizer: [
      new TerserJSPlugin({
        parallel: true,
        terserOptions: {
          compress: {
              warnings: false,
              keep_infinity: true,
              drop_console: true,
              drop_debugger: true,
              pure_funcs: ['console.log'] // 去除console
          },
        },
      }),
    ]
  },

4、splitChunks - 切割chunks

optimization: {
		splitChunks: {
			// chunks: 'all',
                chunks: 'async',
			minSize: 20000,
			// minRemainingSize: 0,
			minChunks: 1,
			maxAsyncRequests: 30,
			maxInitialRequests: 30,
			enforceSizeThreshold: 50000,
			cacheGroups: {
				R3: {
                                    test: /[\\/]node_modules[\\/](@syman)[\\/]/,
                                    name: 'R3',
                                    chunks: 'all',
				},
				BC: {
                                    test: /[\\/]node_modules[\\/](@burgeon)[\\/](business-components)[\\/]/,
                                    name: 'businessComponents',
                                    chunks: 'all',
				},
				I18n: {
                                    test: /[\\/]node_modules[\\/](@burgeon)[\\/](internationalization)[\\/]/,
                                    name: 'internationalization',
                                    chunks: 'all',
				},
				commonLib: {
                                    test: /[\\/]node_modules[\\/]/,
                                    name: 'commonLib',
                                    chunks: 'all',
				},
			},
		},
	},

5、MiniCssExtractPlugin + OptimizeCSSAssetsPluginCssMinimizerWebpackPlugin

用MiniCssExtractPlugin之前:

image.png

用MiniCssExtractPlugin之后:

image.png

用OptimizeCSSAssetsPlugin之后:

image.png

CssMinimizerWebpackPlugin存在版本问题,压缩效果大致同上(基于卡宾当前webpack暂未找到相对应版本

6、productionSourceMap - 去除.map文件

在webpack打包的过程中,打包后每个js文件都有一个map文件,将该多余文件去掉。

map文件的作用:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。 有了map就可以像未加密的代码一样,准确的输出是哪一行哪一列有错。

7、UglifyJsPlugin - 压缩代码并移除console (废弃!!!使用TerserJSPlugin

至少需要 Node v6.9.0Webpack v4.0.0 版本

npm install uglifyjs-webpack-plugin --save-dev
//webpack.config.js
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        uglifyOptions: {
          mangle: true, // 注意 `mangle.properties` 的默认值是 `false`。
          output: {
            comments: false, // 构建时去除注释
          },
        },
        compress: { 
          warnings: false,
          drop_console: true,
          pure_funcs: ['console.log']
        },
        sourceMap: true, // 使用源映射将错误信息位置映射到模块(这将会减慢编译速度)
        extractComments: true, // 是否提取注释到单独的文件中
        test: /.js(?.*)?$/i,  //测试匹配文件,
        include: //includes/, //包含哪些文件
        excluce: //excludes/, //不包含哪些文件

        //允许过滤哪些块应该被uglified(默认情况下,所有块都是uglified)。 
        //返回true以uglify块,否则返回false。
        chunkFilter: (chunk) => {
            // `vendor` 模块不压缩
            if (chunk.name === 'vendor') {
              return false;
            }
            return true;
          }
        }),
  
        cache: false,   //是否启用文件缓存,默认缓存在node_modules/.cache/uglifyjs-webpack-plugin.目录
        parallel: true,  //使用多进程并行运行来提高构建速度
    ],
  },
};

四、Nginx 开启 gzip

...
 
http {
    ...
    
    gzip               on;
    gzip_min_length    1k;
    gzip_buffers       4  16k;
    #gzip_http_version  1.1;
    gzip_comp_level    2; # 压缩级别
    # 要压缩的mine类型
    gzip_types         text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss image/jpeg image/gif image/png image/svg+xml;
    gzip_vary          off;
    gzip_proxied       expired no-cache no-store private auth;
    gzip_disable       "MSIE [1-6]\."; # IE6不支持gzip
    
    ...
}