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.用手机访问页面只需要加载当前访问的页面,不需要预加载,怎么处理?
实现预加载的原理,在 head 里面的 link 标签添加或 rel="preload"与主线并行加载,rel="prefetch"等浏览器空闲时候加载
<head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="icon" href="favicon.ico"> <title>20201107</title> <link href="css/Hello.b6c33b6c.css" rel="prefetch"> <link href="css/Home.6d8963a5.css" rel="prefetch"> <link href="css/about.81902981.css" rel="prefetch"> <link href="js/Hello.785b2111.js" rel="prefetch"> <link href="js/Home.35a910df.js" rel="prefetch"> <link href="js/Home~about~test.106c39ca.js" rel="prefetch"> <link href="js/about.6a93100d.js" rel="prefetch"> <link href="js/test.556b05ca.js" rel="prefetch"> <link href="css/app.d9a200a0.css" rel="preload" as="style"> <link href="css/chunk-vendors.c00f84a3.css" rel="preload" as="style"> <link href="js/app.d87781b6.js" rel="preload" as="script"> <link href="js/chunk-vendors.c2030934.js" rel="preload" as="script"> <link href="css/chunk-vendors.c00f84a3.css" rel="stylesheet"> <link href="css/app.d9a200a0.css" rel="stylesheet"></head> chainWebpack: config => { config.plugins.delete('preload'); config.plugins.delete('prefetch'); }3.优化首屏加载速度(减小打包后 app.js 与 chunk-vendors.js),第三方组件按需加载
router 使用懒加载组件,父组件引入子组件也是如下方式
{ path: '/', component: () => import(/* webpackChunkName: "Home" */ '../views/Home.vue') },@Component({ components: { Hello:() => import(/* webpackChunkName: "Hello", webpackPrefetch: false */ '../components/HelloWorld.vue') }})2.提取页面公共资源
vue,vueRouter,使用 html-webpack-externals-plugin, 降低 chunk-vendors.js 包的大小
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 实现按需加载
npm install babel-plugin-component -D
.babelrc 修改为:
{ "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
在 vue-cli-service build --mode production 默认开启,动态导入 js 无法檫除
如下
import('../units/index' /* webpackChunkName: "pl" */).then((content) => { console.log(content.default()) })2.vue-cli-service build --mode development 则不开启
5.CSS 优化
purgecss-webpack-plugin:删除未使用的 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');可以清除
<style>.style-pl{ color: red;}.head-pl{ position: relative;}
</style>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.压缩图片
image-webpack-loader
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;}版权声明: 本文为 InfoQ 作者【★】的原创文章。
原文链接:【http://xie.infoq.cn/article/d14b0e45e9c154514017a7e6b】。文章转载请联系作者。
★
还未添加个人签名 2020.08.05 加入
还未添加个人简介











评论