Webpack的使用
优化
1.异步加载模块
2.提取第三库
3.代码压缩
4.去除不必要的插件
5.图片base64
6.按需加载
7.开启Gzip压缩
splitChunks拆包
- Webpack4之SplitChunksPlugin
- Webpack3的CommonsChunkPlugin(已废弃)
optimization: {
splitChunks: {
chunks: 'all', // 'initial' | 'async' | 'all'
minSize: 20000, // 生成 chunk 的最小体积
maxSize: 0, // 拆分前最大体积
minChunks: 1, // 被引用次数
maxAsyncRequests: 30, // 按需加载时的最大并行请求数
maxInitialRequests: 30, // 入口点的最大并行请求数
cacheGroups: {
// 第三方库单独打包
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
reuseExistingChunk: true,
},
// 公共代码
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
// 样式文件单独打包
styles: {
test: /\.(css|less|scss)$/,
name: 'styles',
chunks: 'all',
enforce: true,
},
},
},
}
定义全局变量(DefinePlugin)
//eslint 设置通过
"globals": {
"ENV": true
},
new webpack.DefinePlugin({
//必须 JSON.stringify(),然后在eslint里面,global()通过一下
ENV: JSON.stringify(process.env.ENV), // 执行环境
}),
webpack代理
- webpack-dev-server
//在配置文件webpackDevServer.config.js添加,
//新版本直接在package.json 里面添加,但是只能添加一个并且是字符串,也可在src下添加setupProxy.js
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
app.use(
proxy("/pic", {
"target": "http://120.79.229.197:9000",
"changeOrigin": true,
"secure": false,
"pathRewrite": {"^/pic": ""}
})
);
app.use(
proxy("/self", {
"target": "http://localhost:9999",
"changeOrigin": true,
"secure": false,
"pathRewrite": {"^/self": ""}
})
);
};
.babelrc
//新的版本已经支持在package.json里面直接修改
{{
"presets": [
[
"@babel/preset-env", {
"targets": {
"chrome": 58,
"ie": 11
}
}
], "react-app"],
"plugins": [
["import", {
"libraryName": "antd",
"libraryDirectory": "es",
"style": "css"
}
],
["@babel/plugin-proposal-decorators", { "legacy": true }], //用于转换装饰器代码的插件。
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 2,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
],
"env": {
"production": {
"plugins": ["transform-remove-console"]
}
}
}
.env
定义一些环境变量,可以通过process.env.[name]拿取出来
GENERATE_SOURCEMAP=false //禁止输出.map文件
优化输出的文件
/**
* hash:hash是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash值都会更改
* 采用hash计算的话,每一次构建后生成的哈希值都不一样,即使文件内容压根没有改变。这样子是没办法实现缓存效果,我们需要换另一种哈希值计算方式,即chunkhash。
*
* chunkhash:根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。
* 我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。
*
* filename:决定了entry入口文件输出文件的名称。 (main.js)
*
* chunkFilename:决定了非入口(non-entry) chunk 文件的名称,比如按需加载(异步)模块的时候 (组件打包的js)
*/
//js文件的输出
output: {
filename: 'js/[name].[hash:8].js',
chunkFilename: 'js/[name].[chunkhash:8].js'
},
//css文件的输出
miniCssExtractPluginOption: {
filename: 'css/[name].[hash:8].css',
chunkFilename: 'css/[name].[chunkhash:8].css'
},
//img文件的输出
imageUrlLoaderOption: {
limit: 1024*50,
name: 'static/images/[name].[hash:8].[ext]'
},
webpack用到的插件
常用插件配置示例
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const WebpackBundleAnalyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
// 清理输出目录
new CleanWebpackPlugin(),
// 生成 HTML 文件
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html',
chunks: ['index', 'vendors'],
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
},
}),
// 提取 CSS 到单独文件
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].css',
}),
// 定义环境变量
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env.API_URL': JSON.stringify('https://api.example.com'),
}),
// 打包分析(可选)
// new WebpackBundleAnalyzer(),
],
};
require.context是什么
require.context 是 webpack 提供的一个 API,用于创建上下文,实现批量导入模块。
// 语法:require.context(directory, useSubdirectories, regExp)
// directory: 要搜索的目录
// useSubdirectories: 是否搜索子目录
// regExp: 匹配文件的正则表达式
// 示例:批量导入组件
const requireComponent = require.context(
'./components', // 组件目录
true, // 是否查找子目录
/\.vue$/ // 匹配的文件类型
);
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName);
const componentName = fileName
.replace(/^\.\//, '')
.replace(/\.\w+$/, '');
// 全局注册组件
Vue.component(componentName, componentConfig.default || componentConfig);
});
// 示例:批量导入路由
const requireRoute = require.context('./routes', false, /\.js$/);
const routes = requireRoute.keys().map(fileName => {
const route = requireRoute(fileName);
return route.default || route;
});
Tree Shaking
Tree Shaking 用于移除未使用的代码,减少打包体积。
// webpack.config.js
module.exports = {
mode: 'production', // 生产环境自动启用
optimization: {
usedExports: true, // 标记未使用的导出
sideEffects: false, // 告知 webpack 可以安全地删除未使用的导出
},
};
// package.json
{
"sideEffects": [
"*.css",
"*.scss",
"./src/polyfill.js"
]
}
代码懒加载
使用动态 import 实现代码分割和懒加载。
// 路由懒加载
const Home = () => import('./views/Home.vue');
const About = () => import('./views/About.vue');
// 组件懒加载
const HeavyComponent = () => import('./components/HeavyComponent.vue');
// 条件懒加载
if (condition) {
import('./moduleA').then(module => {
// 使用 module
});
}