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 加入
还未添加个人简介
评论