配套代码demo:https://github.com/FinGet/webpack4_demo。博客原文:[https://finget.github.io/2019/07/24/webpack4-0/](https://finget.github.io/2019/07/24/webpack4-0/)
打包多页面在git仓库里,并没有单独写出来。
初始化:
yarn init -y
yarn add webpack webpack-cli -D
webpack-cli的作用就是让我们能在命令行中使用
webpack
、npx webpakck
这些指令。
webpack基础配置
代码语言:javascript复制// webpack 是node写出来,所以要按node的写法
const path = require('path');
module.exports = {
mode: 'development', // 模式 默认值:production [development]
entry: './src/index.js', // 打包入口文件
output: {
filename: 'bundle.[hash:8].js', // 打包后的文件名
path: path.resolve(__dirname, 'dist') // 这个路径必须是一个绝对路径,所以需要用path来解析一下
}
}
代码语言:javascript复制// src/index.js
console.log('hello webpack4.0');
npx webpack
命令直接打包(npm5.2之后支持的语法)。会打包出一个main.js
文件
默认支持js模块化:
代码语言:javascript复制// commonjs
// src/a.js
module.exports = 'FinGet'
// src/index.js
let name = require('./a.js');
console.log(name); // 'FinGet'
代码语言:javascript复制// ES6 module
// src/a.js
export default = 'FinGet'
// src/index.js
import name from './a.js'
console.log(name); // 'FinGet'
手动配置webpack
- 默认配置文件的名字:
webpack.config.js
。为啥叫这个名字呢?
// node_modules/webpack-cli/bin/config/config-yargs.js
...
module.exports = function(yargs) {
yargs
.help("help")
.alias("help", "h")
.version()
.alias("version", "v")
.options({
config: {
type: "string",
describe: "Path to the config file",
group: CONFIG_GROUP,
defaultDescription: "webpack.config.js or webpackfile.js", // 默认名字有两种
requiresArg: true
},
...
- 可以通过–config指定配置文件: npx webpack --config xxxx.js
- 也可以在
package.json
中配置脚本
"script": {
"build": "webpack --config webpack.config.my.js"
},
运行 npm run build
- 如果在
package.json
中不设置config文件
"script": {
"build": "webpack"
},
运行 npm run build -- --config webpack.config.my.js
--
不能少!
- 简化的webpack打包出来的文件:
(function(modules) { // webpackBootstrap
// The module cache 先定义一个缓存
var installedModules = {};
// The require function 配置了一个require方法
function __webpack_require__(moduleId) {
// Check if module is in cache 检查这个模块是否在缓存中
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// Create a new module (and put it into the cache) 创建一个新的模块,并存入缓存
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
// Execute the module function
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// Flag the module as loaded
module.l = true;
// Return the exports of the module
return module.exports;
}
// Load entry module and return exports 加载入口模块
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})({
// key-value key -> 模块路径 | value -> 函数
"./src/a.js": (function(module, exports) {
eval("module.exports="FinGet";nn//# sourceURL=webpack:///./src/a.js?");
}),
"./src/index.js": (function(module, exports, __webpack_require__) {
eval("let name = __webpack_require__(/*! ./a.js */ "./src/a.js");nconsole.log('hello webpack4.0');nconsole.log(name);nn//# sourceURL=webpack:///./src/index.js?");
})
});
webpack-dev-server
yarn add webpack-dev-server -D
它会在内存中生成打包文件。
官方文档: https://webpack.docschina.org/configuration/dev-server/
本地服务
代码语言:javascript复制// webpack.config.js
// 开发服务器的配置 官方文档: https://webpack.docschina.org/configuration/dev-server/
devServer: {
contentBase: './dist', // 告诉服务器从哪个目录中提供内容。只有在你想要提供静态文件时才需要。
publicPath: './dist', // 将用于确定应该从哪里提供 bundle,并且此选项优先。 此路径下的打包文件可在浏览器中访问。
port: 3000, // 端口
progress: true, // 打包过程
open: true, // 自动打开浏览器
compress: true, // 一切服务都启用 gzip 压缩
// host: '' , // 指定使用一个 host
hot: true, // 启用 webpack 的 模块热替换 功能 依赖于HotModuleReplacementPlugin
}
plugins: [
// 开启webpack全局热更新
new webpack.HotModuleReplacementPlugin()
]
做代理
代码语言:javascript复制devServer : {
proxy: { // 代理
'/api': {
target: 'http://localhost:3000',
pathRewrite: {'^/api' : ''}
}
}
}
mock数据
代码语言:javascript复制devServer: {
// 前端mock数据 不存在跨域
before(app) {
app.get('/api/goods', (req, res) => {
res.json({
code: 0,
list: [
{id:1,name:'苹果'},
{id:2,name:'香蕉'}
]
})
})
}
}
html-webpack-plugin
yarn add html-webpack-plugin -D
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'./public/index.html'), // 模版路径
filename: 'index.html', // 打包后的文件名
title: 'webpack4.0', // 顾名思义,设置生成的 html 文件的标题
/**
注入选项。有四个选项值 true, body, head, false
true 默认值,script标签位于html文件的
body 底部body 同 true
head script 标签位于 head 标签内
false 不插入生成的 js 文件,只是单纯的生成一个 html 文件
*/
inject: true,
// favicon: 'xxx.ico' // 给生成的 html 文件生成一个 favicon
minify: { // 压缩
removeAttributeQuotes: true, // 去掉属性的双引号
collapseWhitespace: true // 代码压缩成一行
},
hash: true, // hash选项的作用是 给生成的 js 文件一个独特的 hash 值,该 hash 值是该次 webpack 编译的 hash 值
cahe: true, // 默认值是 true。表示只有在内容变化时才生成一个新的文件
showErrors: true, // 如果 webpack 编译出现错误,webpack会将错误信息包裹在一个 pre 标签内,属性的默认值为 true
/**
chunks 选项的作用主要是针对多入口(entry)文件。当你有多个入口文件的时候,对应就会生成多个编译后的 js 文件。那么 chunks 选项就可以决定是否都使用这些生成的 js 文件。
chunks 默认会在生成的 html 文件中引用所有的 js 文件,当然你也可以指定引入哪些特定的文件。
**/
// chunks: ['index','index2'],
})
]
css样式
yarn add css-loader style-loader less less-loader -D
在index.js中引入css|less模块
代码语言:javascript复制// src/index.js
let name = require('./a.js');
require('./assets/css/index.css');
require('./assets/css/commom.less');
console.log('hello webpack4.0');
console.log(name);
代码语言:javascript复制module: { // 模块
rules: [
// loader的顺序 默认是从右往左,从上到下
// css-loader 解析 @import 这种语法的
// style-loader 将css引入html的head中 style标签
// {test: /.css$/, use: ['style-loader','css-loader']}
{test: /.(css|less)$/,
use: [
{
loader: 'style-loader',
options: {
insertAt: 'top' // 插入顶部 这样就会被后面的样式覆盖
}
},
'css-loader',
'less-loader'
]
}
]
},
mini-css-extract-plugin
yarn add mini-css-extract-plugin -D
上面打包css会把css文件以style标签的形式写入index.html
,现在我们就来把它们单独打包成文件。
module: { // 模块
rules: [
{test: /.(css|less)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'assets/css/index.css' // 打包到dist/assets/css/index.css
})
]
css3 自动添加各种浏览器前缀:
yarn add postcss-loader autoprefixer -D
// postcss.config.js
module.exports = {
plugins: [require('autoprefixer')({'browsers': ['> 1%', 'last 2 versions']})]
}
// webpack.config.js
module: { // 模块
rules: [
{test: /.(css|less)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'less-loader'
]
}
]
},
推荐用法是在package.json
中设置:
代码语言:javascript复制Replace Autoprefixer browsers option to Browserslist config. Use browserslist key in package.json or .browserslistrc file.
// postcss.config.js
module.exports = {
plugins: [require('autoprefixer')]
}
代码语言:javascript复制"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
压缩css:
⚠️压缩css也要压缩js,不如js不会压缩。
yarn add optimize-css-assets-webpack-plugin terser-webpack-plugin -D
// webpack.config.js
mode:'production', // * development不会压缩
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
处理js
yarn add babel-loader @babel/babel-core @babel/preset-env -D
代码语言:javascript复制⚠️
@babel/babel-core
和@babel/preset-env
与babel-core
和babel-preset-env
不一样
// webpack.config.js
module: {
rules: [
{
test: /.js$/,
exclude: '/node_modules',
include: 'src',
use: {
loader: 'babel-loader',
options: {
// 配置预设
presets: [
'@babel/preset-env'
]
}
}
}
]
}
或者:
代码语言:javascript复制// .babelrc
{
"presets": ["@babel/preset-env"]
}
处理高级版本js
babel-runtime 是供编译模块复用工具函数,是锦上添花。 babel-polyfil是雪中送炭,是转译没有的api。
详细讲解
代码语言:javascript复制// 示例
class Person{
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let person = new Person('FinGet',24);
console.log(person.name);
// 高级api
console.log('FinGet'.includes('Get'));
代码语言:javascript复制yarn add @babel/plugin-transform-runtime -D
// @babel/runtime as a production dependency (since it's for the "runtime").
yarn add @babel/runtime
使用:
代码语言:javascript复制// .babelrc
"plugins": ["@babel/plugin-transform-runtime"]
代码语言:javascript复制
@babel/runtime
会在打包的js中,注入一些脚本,所以要安装production依赖
yarn add @babel/polyfill
使用:
代码语言:javascript复制require("@babel/polyfill");
// or
import "@babel/polyfill";
// or
// webpack.config.js
module.exports = {
entry: ["@babel/polyfill", "./app/js"],
};
这样引入会导致打包出来的js很大
按需引入:
代码语言:javascript复制// .babelrd
{
"presets": [["@babel/preset-env", {
"useBuiltIns": "usage"
}]],
}
关键点是useBuiltIns
这一配置项,它的值有三种:
false
: 不对polyfills
做任何操作entry
: 根据target
中浏览器版本的支持,将polyfills
拆分引入,仅引入有浏览器不支持的polyfill
usage
(新):检测代码中ES6/7/8等的使用情况,仅仅加载代码中用到的polyfills
ESlint 检测语法
代码语言:javascript复制yarn add eslint eslint-loader -D
https://cn.eslint.org/demo/
在根目录下生成一个.eslint.json
来配置规则。
{
"parserOptions": {
"ecmaVersion": 5,
"sourceType": "script",
"ecmaFeatures": {}
},
"rules": {
// 允许console
"no-console": "off",
// 允许空语句块
"no-empty": ["error", { "allowEmptyCatch": true }],
// 强制关键字周围空格的一致性 (keyword-spacing)
"keyword-spacing": "error",
// 把 var 语句看作是在块级作用域范围之内
"block-scoped-var": "error",
// 要求遵循大括号约定
"curly": "error",
// switch 要有default分支
"default-case": "error",
// no-eq-null 禁止与null进行比较
"no-eq-null": "error",
// 禁止使用多个空格
"no-multi-spaces": ["error", {"exceptions": { "Property": true }}],
// 禁止多行字符串
"no-multi-str": "error",
// 禁止使用 new 以避免产生副作用
"no-new": "error",
// 数组中的空格
"array-bracket-spacing": ["error", "never"],
// 禁止或强制在代码块中开括号前和闭括号后有空格
"block-spacing": "error",
// 大括号风格要求
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
// 逗号前后使用一致的空格
"comma-spacing": ["error", { "before": false, "after": true }],
// 逗号风格
"comma-style": ["error", "last"],
// 计算属性不使用空格
"computed-property-spacing": ["error", "never"],
// 函数标识符和其调用之间禁止空格
"func-call-spacing": ["error", "never"],
// 箭头函数函数体的位置
"implicit-arrow-linebreak": ["error", "beside"],
// tab缩进
"indent": ["error", "tab", { "SwitchCase": 1 }],
// 对象key-value空格
"key-spacing": ["error", { "beforeColon": false }],
// 行注释位置
"line-comment-position": ["error", { "position": "above" }],
// 类成员之间需要空行
"lines-between-class-members": ["error", "always"],
// 要求构造函数首字母大写
"new-cap": "error",
// 调用无参构造函数时带括号
"new-parens": "error",
// 禁止使用 Array 构造函数
"no-array-constructor": "error",
// 禁止使用内联注释
"no-inline-comments": "error",
// 禁止连续赋值
"no-multi-assign": "error",
// 不允许多个空行
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
// 禁止使用 Object 构造函数
"no-new-object": "error",
// 禁用行尾空白
"no-trailing-spaces": "error",
// 禁止属性前有空白
"no-whitespace-before-property": "error",
// 强制在花括号内使用一致的换行符
"object-curly-newline": ["error", { "ImportDeclaration": "always", "ExportDeclaration": "always" }],
// 花括号中使用一致的空格
"object-curly-spacing": ["error", "never"],
// 要求在变量声明周围换行
"one-var-declaration-per-line": ["error", "always"],
// 禁止块内填充
"padded-blocks": ["error", "never"],
// 语句间填充空行
"padding-line-between-statements": [
"error",
{ "blankLine": "always", "prev": ["const", "let", "var"], "next": "*"},
{ "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]},
{ "blankLine": "always", "prev": "directive", "next": "*" },
{ "blankLine": "any", "prev": "directive", "next": "directive" }
],
// 强制使用一致的反勾号、双引号或单引号
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
// 对象字面量属性名称使用引号
"quote-props": ["error", "as-needed"],
// 行尾分号
"semi": ["error", "always"],
// 分号前后空格
"semi-spacing": ["error", {"before": false, "after": true}],
// 分号位置
"semi-style": ["error", "last"],
// 语句块之前的空格
"space-before-blocks": "error",
// function空格
"space-before-function-paren": ["error", {
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}],
// 禁止圆括号内的空格
"space-in-parens": "error",
// 要求中缀操作符周围有空格
"space-infix-ops": "error",
// 要求或禁止在一元操作符之前或之后存在空格
"space-unary-ops": ["error", {"words": true, "nonwords": false}],
// 要求或禁止在注释前有空白
"spaced-comment": ["error", "always"],
// 强制在 switch 的冒号左右有空格
"switch-colon-spacing": "error",
// 要求正则表达式被包裹起来
"wrap-regex": "error",
// ES6
// 要求箭头函数体使用大括号
"arrow-body-style": "error",
// 要求箭头函数的箭头之前或之后有空格
"arrow-spacing": "error",
// 禁止重复导入
},
"env": {}
}
代码语言:javascript复制{
test: /.js$/,
loader: ['babel-loader', 'eslint-loader'],
}
// or
{
test: /.js$/,
use: {
loader: 'eslint-loader',
options: {
enforce: 'pre' // 先执行
}
}
}
打包图片
- js中创建图片引入
import jpg from './assets/snail.jpg'
let img = new Image();
img.src = jpg
document.body.appendChild(img);
- css背景图引入
body{
background-image: url(../logo.svg);
}
- html img标签引入
<img src="../src/assets/snail.jpg" alt="">
file-loader
代码语言:javascript复制yarn add file-loader -D
file-loader
会默认在内部生成生成一张图片,到dist目录下,把生成图片的名字返回回来
{
test: /.(png|jpe?g|gif|svg)(?.*)?$/,
use: 'file-loader'
}
html-withimg-loader
代码语言:javascript复制html中直接使用img标签src加载图片的话,因为没有被依赖,图片将不会被打包。
yarn add html-withimg-loader
使用:
代码语言:javascript复制{
test: /.(htm|html)$/i,
loader: 'html-withimg-loader'
}
url-loader
如果图片较多,会发很多http请求,会降低页面性能。这个问题可以通过url-loader解决。url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。当然,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行copy。
代码语言:javascript复制url-loader和file-loader是什么关系呢?简答地说,url-loader封装了file-loader。url-loader不依赖于file-loader,即使用url-loader时,只需要安装url-loader即可,不需要安装file-loader,因为url-loader内置了file-loader。
yarn add url-loader -D
代码语言:javascript复制{
test: /.(png|jpe?g|gif|svg)(?.*)?$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]', // 保持名称不变
limit: 20*1024, // 小于20k的图片 打包成base64
outputPath: 'assets/' // 打包后的存放路径 dist/assets
}
}
},
output.publicPath
代码语言:javascript复制此选项指定在浏览器中所引用的「此输出目录对应的公开 URL」。相对 URL(relative URL) 会被相对于 HTML 页面(或 标签)解析。相对于服务的 URL(Server-relative URL),相对于协议的 URL(protocol-relative URL) 或绝对 URL(absolute URL) 也可是可能用到的,或者有时必须用到,例如:当将资源托管到 CDN 时。
module.exports = {
//...
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: 'https://cdn.example.com/assets/'
}
};
⚠️也可以单独给图片的options下配一个publicPath
source-map
生产模式会压缩代码成一行,就没法调试了。
代码语言:javascript复制...
️mode:'developmen', //production 不会生成map文件
entry: './src/index.js',
devtool: "source-map", // 增加映射文件
...
webpack 高级配置
watch
代码语言:javascript复制...
entry: entry: './src/index.js',
// build 监控,变化自动打包
watch: true,
watchOptions: { // 监控选项
poll: 1000, // 每秒 watch 1000次
aggregateTimeout: 500, // 防抖
ignored: '/node_modules/' //不需要监控的文件
},
...
clean-webpack-plugin
每次打包之前,都删除dist目录下的文件。
代码语言:javascript复制yarn add clean-webpack-plugin -D
clean-webpack-plugin: ^3.00
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
plugins: [
new CleanWebpackPlugin()
]
代码语言:javascript复制export { CleanWebpackPlugin };//3.0.0导出方式
export default CleanWebpackPlugin;//2.0.2导出方式
所以在2.0.2版本我们可以直接require拿到CleanWebpackPlugin
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = CleanWebpackPlugin;//1.0.1导出方式
代码语言:javascript复制他会默认清空我们output里面设置的所有文件夹
https://github.com/johnagan/clean-webpack-plugin#options-and-defaults-optional
By default, this plugin will remove all files inside webpack's output.path directory, as well as all unused webpack assets after every successful rebuild.
copy-webpack-plugin
拷贝文件
代码语言:javascript复制yarn add copy-webpack-plugin -D
代码语言:javascript复制const CopyPlugin = require('copy-webpack-plugin');
plugins: [
new CopyPlugin([
{ from: 'src/assets', to: 'assets' }
]),
]
BannerPlugin
版权声明
代码语言:javascript复制plugins:[
new webpack.BannerPlugin('CopyRight by FinGet!')
]
// 会在打包文件头部加上 /*! CopyRight by FinGet! */
代码语言:javascript复制// 配置选项
{
banner: string | function, // 其值为字符串或函数,将作为注释存在
raw: boolean, // 如果值为 true,将直出,不会被作为注释
entryOnly: boolean, // 如果值为 true,将只在入口 chunks 文件中添加
test: string | RegExp | Array,
include: string | RegExp | Array,
exclude: string | RegExp | Array,
}
resolve
代码语言:javascript复制module.exports = {
resolve: { // 解析第三方包
alias: { // 创建 import 或 require 的别名,来确保模块引入变得更简单。
'@': path.resolve(__dirname, 'src')
},
extensions: ['.js','.css','.json'], // 自动解析确定的扩展 就是没有后缀名时,按这个顺序匹配
modules: [path.resolve('node_modules')] //告诉 webpack 解析模块时应该搜索的目录
},
}
点这里查看更多配置项。
DefinePlugin
定义一些全局变量。
代码语言:javascript复制module.exports = {
plugins: [
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify('5fa3b9'),
BROWSER_SUPPORTS_HTML5: true,
TWO: '1 1',
'typeof window': JSON.stringify('object'),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
});
]
}
注意,因为这个插件直接执行文本替换,给定的值必须包含字符串本身内的实际引号。通常,有两种方式来达到这个效果,使用 ‘“production”‘, 或者使用 JSON.stringify(‘production’)。
webpack-merge
分别配置不同的环境打包文件。
代码语言:javascript复制yarn add webpack-merge -D
代码语言:javascript复制// build/webpack.base.conf.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: path.resolve(__dirname,'../src/index.js'), // 打包入口文件
output: {
filename: 'bundle.[hash:8].js', // 打包后的文件名
path: path.resolve(__dirname, '../dist') // 这个路径必须是一个绝对路径,所以需要用path来解析一下
},
module: { // 模块
rules: [
{
test: /.(css|less)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'less-loader'
]
},
{
test: /.js$/,
loader: 'babel-loader',
},
{
test: /.(png|jpe?g|gif|svg)(?.*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 1,
outputPath: 'assets/images' // 打包后的存放路径
}
}
},
{
test: /.(htm|html)$/i,
loader: 'html-withimg-loader'
}
]
},
// 配置插件
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html'), // 模版路径
filename: 'index.html', // 打包后的文件名
title: 'webpack4.0', // 顾名思义,设置生成的 html 文件的标题
inject: true,
hash: true, // hash选项的作用是 给生成的 js 文件一个独特的 hash 值,该 hash 值是该次 webpack 编译的 hash 值
cahe: true, // 默认值是 true。表示只有在内容变化时才生成一个新的文件
showErrors: true, // 如果 webpack 编译出现错误,webpack会将错误信息包裹在一个 pre 标签内,属性的默认值为 true
}),
new MiniCssExtractPlugin({
filename: 'assets/css/index.css'
})
]
}
代码语言:javascript复制// build/webpack.pro.cong.js
const merge = require('webpack-merge');
const base = require('./webpack.base.conf');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
mmodule.exports = merge(base, {
mode: 'production',
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
plugins: [
// 文件头部注入
new webpack.BannerPlugin('CopyRight by FinGet!')
]
})
代码语言:javascript复制// build/webpack.dev.cong.js
const merge = require('webpack-merge');
const webpack = require('webpack');
const base = require('./webpack.base.conf');
mmodule.exports = merge(base, {
mode: 'development',
// 开发服务器的配置 官方文档: https://webpack.docschina.org/configuration/dev-server/
devServer: {
contentBase: path.resolve(__dirname, "../dist"), // 告诉服务器从哪个目录中提供内容。只有在你想要提供静态文件时才需要。
// publicPath: './dist', // 将用于确定应该从哪里提供 bundle,并且此选项优先。 此路径下的打包文件可在浏览器中访问。
port: 3000, // 端口
progress: true, // 打包过程
open: true, // 自动打开浏览器
},
devtool: 'source-map',
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
})
],
})
代码语言:javascript复制yarn run dev -- --config build/webpack.dev.conf.js
yarn run build -- --config build/webpack.pro.conf.js
webpack 优化
noParse
防止 webpack 解析那些任何与给定正则表达式相匹配的文件。
代码语言:javascript复制module.exports = {
//...
module: {
noParse: /jquery|lodash/,
}
};
happyPack 多线程打包
js、css、img都可以多线程打包,提高打包速度。
代码语言:javascript复制yarn add happypack -D
代码语言:javascript复制module.exports = {
module:{
{
test: /.js$/,
use: 'Happypack/loader?id=js'
}
}
plugins:[
new Happypack({
id: 'js', // id与上面对应
use: [{
loader: 'babel-loader',
options: {
presets:['@babel/preset-env']
}
}]
})
]
}
tree-shaking
(webpack 自带)把没用的代码删除掉。
代码语言:javascript复制
import
在生产环境下 会自动去掉没用的代码。es6 模块会把结果放到default
上。
// test.js
let sum = (a,b) => {
return a b;
}
let minus = (a,b) => {
return a-b;
}
export default {sum,minus}
代码语言:javascript复制import calc from './test.js';
console.log(calc.add(1,2));
let calc = require('./test');
console.log(calc.default.sum(1,2));
这里没用minus
方法,在import
方式打包中会tree-shaking
,require
则不会。
scope hosting
代码语言:javascript复制let a = 1;
let b = 2;
let c = 3;
let d = a b c;
console.log(d);
这个代码很啰嗦,在打包之后,webpack会自动分析,省略代码。
代码语言:javascript复制// 打包后
console.log(6);
抽离公共代码
多入口项目,多个入口,引用同一个js/css,则可以抽离公共代码。
代码语言:javascript复制module.exports = {
optimization: {
splitChunks: { // 分割代码块
cacheGroups: { // 缓存组
common: { // 公共模块
chunks: 'initial',
minSize: 0,
minChunks: 2,
}
}
}
},
}
代码语言:javascript复制// 把第三方模块单独打包 比如jquery、lodash
module.exports = {
optimization: {
splitChunks: { // 分割代码块
cacheGroups: { // 缓存组
common: { // 公共模块
chunks: 'initial',
minSize: 0,
minChunks: 2,
},
// 单独打包第三方模块
vendor: {
priority: 1, // 优先级别
test: /[\/]node_modules[\/]/,
chunks: 'initial',
name(module, chunks, cacheGroupKey) {
const moduleFileName = module.identifier().split('/').reduceRight(item => item);
return `${moduleFileName}`;
},
minSize: 0,
minChunks: 2
}
}
}
},
}
optimization参数介绍:
代码语言:javascript复制optimization: {
splitChunks: {
chunks: "initial", // 代码块类型 必须三选一: "initial"(初始化) | "all"(默认就是all) | "async"(动态加载)
minSize: 0, // 最小尺寸,默认0
minChunks: 1, // 最小 chunk ,默认1
maxAsyncRequests: 1, // 最大异步请求数, 默认1
maxInitialRequests: 1, // 最大初始化请求书,默认1
name: () => {}, // 名称,此选项课接收 function
cacheGroups: { // 缓存组会继承splitChunks的配置,但是test、priorty和reuseExistingChunk只能用于配置缓存组。
priority: "0", // 缓存组优先级 false | object |
vendor: { // key 为entry中定义的 入口名称
chunks: "initial", // 必须三选一: "initial"(初始化) | "all" | "async"(默认就是异步)
test: /react|lodash/, // 正则规则验证,如果符合就提取 chunk
name: "vendor", // 要缓存的 分隔出来的 chunk 名称
minSize: 0,
minChunks: 1,
enforce: true,
reuseExistingChunk: true // 可设置是否重用已用chunk 不再创建新的chunk
}
}
}
}
点击这里查看更多配置。
懒加载
在用户触发一个点击操作才加载需要的文件。
代码语言:javascript复制// lazy.js
export default '懒加载';
代码语言:javascript复制// test.js
function handleClick() {
import('./lazy.js').then(module => {
console.log(module.default);
})
}