Bootstrap

vue+webpack+vue-cli

1.Vue.component()与Vue.use()会导致webpack打包产生的chunk-vendors.js过大会造成首页加首次载缓慢?

Object.values(element).map((e: any)=> {
  if (!e.__file && !e.name) return
  Vue.component('Ca' + e.name, e)
})

应该提取基础组件例如高频使用的组件加入劝阻注册

2.用手机访问页面只需要加载当前访问的页面,不需要预加载,怎么处理?

    
    
    
    
    20201107
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    chainWebpack: config => {
        config.plugins.delete('preload');
        config.plugins.delete('prefetch');
    }
3.优化首屏加载速度(减小打包后app.js与chunk-vendors.js),第三方组件按需加载
  {
    path: '/',
    component: () => import(/* webpackChunkName: "Home" */ '../views/Home.vue')
  },

@Component({
    components: {
        Hello:() => import(/* webpackChunkName: "Hello", webpackPrefetch: false */ '../components/HelloWorld.vue')
    }
})

2.提取页面公共资源

        plugins: [
            new HtmlWebpackExternalsPlugin({
                externals: [
                    {
                        module: 'vue',
                        entry: 'https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js',
                        global: 'Vue',
                    },
                    {
                        module: 'vue-router',
                        entry: 'https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js',
                        global: 'VueRouter',
                    },
                    {
                        module: 'google-roboto',
                        entry: {
                          path: 'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
                          type: 'css',
                        },
                      },                
                ],
            }),
        ]

3.引用element-ui实现按需加载

{
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

4.webpack使用SplitChunksPlugin实现公共代码抽离代码抽离

optimization: {
    splitChunks: {
      chunks: 'async|all', // 模块异步  
      minSize: 20000,// 20k
      minRemainingSize: 0,
      minChunks: 1, // 被引用次数,到达多少开始抽离
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
    },
  },
4.在项目中写了很多没有用到的代码,打包到了服务器上,浪费了资源加载怎么处理?

使用Tree Shaking擦除无用的JavaScript和CSS

如下

         import('../units/index' /* webpackChunkName: "pl" */).then((content) => {
             console.log(content.default())
         })

2.vue-cli-service build --mode development 则不开启

5.CSS优化
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const glob = require('glob')
const PATHS = {
  src: path.join(__dirname, 'src')
}

new PurgeCSSPlugin({
  paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
})

注意:写在组件里面的css并不会被清除掉,通过@import url('../less.less');可以清除

2.mini-css-extract-plugin:将CSS提取到单独的文件中。它为每个包含CSS的JS文件创建一个CSS文件。它支持CSS和SourceMap的按需加载(vuecli内置了此插件)

chainWebpack(config) {
	config.when(process.env.NODE_ENV !== 'development', config => {
		config.plugin('extract-css').tap(options => {
        	options[0].filename = 'static/css/[name].[hash:8].css'
        	return options
      })
	}
}
6.安装sass,目前装以下版本,高版本报错

"node-sass""^4.11.0", "sass-loader""^7.1.0",

7.压缩图片
        config.module
            .rule('graphql')
            .test(/\.(gif|png|jpe?g|svg)$/i)
            .use('file-loader')
            .loader('image-webpack-loader')
            .tap(options => {
                // 修改它的选项...
                return options = {
                    mozjpeg: {
                        progressive: true,
                    },
                    // optipng.enabled: false will disable optipng
                    optipng: {
                        enabled: false,
                    },
                    pngquant: {
                        quality: [0.65, 0.90],
                        speed: 4
                    },
                    gifsicle: {
                        interlaced: false,
                    },
                    // the webp option will enable WEBP
                    webp: {
                        quality: 75
                    }
                }
            })
            .end()

注意:出现Error: Cannot find module 'imagemin-gifsicle'报错,卸掉插件在安装 npm un image-webpack-loader

8.gzip优化
const CompressionPlugin = require("compression-webpack-plugin");
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg|ttf|woff)(\?.*)?$/i;
new CompressionPlugin({
  test: productionGzipExtensions,
  deleteOriginalAssets: true, // 是否删除原资源
}),
9.完整配置
const glob = require('glob')
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
const CompressionPlugin = require("compression-webpack-plugin");
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg|ttf|woff)(\?.*)?$/i;
const { join } = require('path')
const PATHS = {
    src: join(__dirname, 'src')
}
module.exports = {
    publicPath: './',
    productionSourceMap: false, // 关掉map
    configureWebpack: {
        plugins: [
            new HtmlWebpackExternalsPlugin({
                externals: [
                    {
                        module: 'vue',
                        entry: 'https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js',
                        global: 'Vue',
                    },
                    {
                        module: 'vue-router',
                        entry: 'https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js',
                        global: 'VueRouter',
                    },
                    {
                        module: 'google-roboto',
                        entry: {
                            path: 'https://unpkg.com/element-ui/lib/theme-chalk/index.css',
                            type: 'css',
                        },
                    },
                ],
            }),
            new PurgeCSSPlugin({
                paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
            }),
            new CompressionPlugin({
                test: productionGzipExtensions,
                deleteOriginalAssets: true, // 是否删除原资源
            }),
        ]
    },
    chainWebpack: config => {
        config.plugins.delete('preload');
        config.plugins.delete('prefetch');
        config.optimization.splitChunks({
            chunks: 'all',
            minSize: 20000,
            minChunks: 1,
        });

        config.module
            .rule('image-loader')
            .test(/\.(gif|png|jpe?g|svg)$/i)
            .use('file-loader')
            .loader('image-webpack-loader')
            .tap(options => {
                // 修改它的选项...
                return options = {
                    mozjpeg: {
                        progressive: true,
                    },
                    // optipng.enabled: false will disable optipng
                    optipng: {
                        enabled: false,
                    },
                    pngquant: {
                        quality: [0.65, 0.90],
                        speed: 4
                    },
                    gifsicle: {
                        interlaced: false,
                    },
                    // the webp option will enable WEBP
                    webp: {
                        quality: 75
                    }
                }
            })
            .end()

    }
    // devServer: {
    //     proxy: {
    //         '/': { //访问路径,可以自己设置,
    //             target: 'http://xxx:8000/', //代理接口,即后端运行所在的端口
    //             changeOrigin: true, //设置是否跨域
    //             ws: true,
    //             // pathRewrite: { //访问路径重写
    //             //     '^/activity/babao_dan/save': 'sss'
    //             // }
    //         }
    //     }
    // }
}
10.动态导出模块
 const files = require.context(
  directory, // 目录,必须写死
  (useSubdirectories = true), // 是否递归
  (regExp = /^\.\/.*$/), // 匹配文件
  (mode = 'sync') // 同步
);
导出的功能有3个属性:resolve,keys,id。
resolve 是一个函数,并返回已解析请求的模块ID。
keys 是一个函数,它返回上下文模块可以处理的所有可能请求的数组

sync 直接打包到当前文件,同步加载并执行
lazy 延迟加载会分离出单独的 chunk 文件
lazy-once 延迟加载会分离出单独的 chunk 文件,加载过下次再加载直接读取内存里的代码。
eager 不会分离出单独的 chunk 文件,但是会返回 promise,只有调用了 promise 才会执行代码,可以理解为先加载了代码,但是我们可以控制延迟执行这部分代码
/**
 * @description: 匹配相应组件方法
 * @param {any} 文件信息
 * @return {any} 组件信息
 */
function componentFn(files: any) {
    const components: any = {};
    files.keys().forEach((key: string) => {
        const name = (require('path').basename(key, '.vue') || files(key).default.name).toLocaleLowerCase();
        const file = files(key).default || files(key);
        components[`mr-${name}`] = file;
    });
    return components;
}