# entry 和 output
output中的path必须是个
绝对路径而不是相对路径, 而且path虽然默认是dist,但是如果不配置的话,会导致clean-webpack-plugin不清理dist包
const path = require('path') ;
let htmlwebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports={
mode:'production',
// entry相对路径和绝对路径都行
entry:{
main:"./index.js",//main作为默认名
sub:'./index.js'
},
// 必须是绝对路径
output:{
publicPath:'https://xx.cdn.com',//前缀
chunkFileName:"[name].xxxx.js"//非入口文件的其他文件打包后命名
filename:'[name].js',
// filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中,这样文件按文件夹管理比较清晰
path:path.resolve(__dirname,'zip')
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ceshi1</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="https://xx.cdn.com/main.js"></script>
<script type="text/javascript" src="https://xx.cdn.com/sub.js"></script></body>
</html>
# webpack entry单个入口(简写)语法
用法:entry: string | [string]
module.exports = {
// 入口文件,默认src/main.js
entry: './path/to/my/entry/file.js',
};
entry 属性的单个入口语法,是以下形式的简写:
module.exports = {
entry: {
main: './path/to/my/entry/file.js',
},
};
也可以将一个文件路径数组传递给 entry 属性,这将创建一个所谓的 "multi-main entry"。想要一次注入多个依赖文件,并且将它们的依赖关系绘制在一个 "chunk" 中时,这种方式就很有用。
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],// 这两个文件打包成一个输出文件
output: {
filename: 'bundle.js',
},
};
# webpack entry 对象写法
用法:entry: { <entryChunkName> string | [string] } | {}
module.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js',
},
};
对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式。
entry:{
main1:['./index.js','./demo'], //index.js 和demo.js可以合并到同一个文件,同时可以省略掉后缀
merge:'./merge.js'
}
// 最后会生成两个文件main1 和 merge
# 描述入口的对象
用于描述入口的对象。你可以使用如下属性:
- dependOn: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。
- filename: 指定要输出的文件名称。
- import: 启动时需加载的模块。
- library: 指定 library 选项,为当前 entry 构建一个 library。
- runtime: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false 以避免一个新的运行时 chunk。
- publicPath: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。请查看 output.publicPath。
runtime 和 dependOn 不应在同一个入口上同时使用,所以如下配置无效,并且会抛出错误:
module.exports = {
entry: {
a2: './a',
b2: {
runtime: 'x2',
dependOn: 'a2',
import: './b',
},
},
};
确保 runtime 不能指向已存在的入口名称,例如下面配置会抛出一个错误:
module.exports = {
entry: {
a1: './a',
b1: {
runtime: 'a1',
import: './b',
},
},
};
另外 dependOn 不能是循环引用的,下面的例子也会出现错误:
module.exports = {
entry: {
a3: {
import: './a',
dependOn: 'b3',
},
b3: {
import: './b',
dependOn: 'a3',
},
},
}
# 常见场景
分离 app(应用程序) 和 vendor(第三方库) 入口 webpack.config.js
module.exports = {
entry: {
main: './src/app.js',
vendor: './src/vendor.js',
},
};
webpack.prod.js
module.exports = {
output: {
filename: '[name].[contenthash].bundle.js',
},
};
webpack.dev.js
module.exports = {
output: {
filename: '[name].bundle.js',
},
};
这是什么? 这是告诉 webpack 我们想要配置 2 个单独的入口点(例如上面的示例)。
为什么? 这样就可以在 vendor.js 中存入未做修改的必要 library 或文件(例如 Bootstrap, jQuery, 图片等),然后将它们打包在一起成为单独的 chunk。内容哈希保持不变,这使浏览器可以独立地缓存它们,从而减少了加载时间。
# 多页面应用程序
webpack.config.js
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js',
},
};
打包代码时会将所有 js 文件打包到一个文件中,体积太大了。如果只要渲染首页,就应该只加载首页的 js 文件,其他文件不应该加载。
所以需要将打包生成的文件进行代码分割,生成多个 js 文件,渲染哪个页面就只加载某个 js 文件,这样加载的资源就少,速度就更快。
代码分割(Code Split)主要做了两件事:
- 分割文件:将打包生成的文件进行分割,生成多个 js 文件。
- 按需加载:需要哪个文件就加载哪个文件。
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// 单入口
// entry: './src/main.js',
// 多入口
entry: {
main: "./src/main.js",
app: "./src/app.js",
},
output: {
path: path.resolve(__dirname, "./dist"),
// [name]是webpack命名规则,使用chunk的name作为输出的文件名。
// 什么是chunk?打包的资源就是chunk,输出出去叫bundle。
// chunk的name是啥呢? 比如: entry中xxx: "./src/xxx.js", name就是xxx。注意是前面的xxx,和文件名无关。
// 为什么需要这样命名呢?如果还是之前写法main.js,那么打包生成两个js文件都会叫做main.js会发生覆盖。(实际上会直接报错的)
filename: "js/[name].js",
clear: true,
},
mode: "production",
};
配置了几个入口,至少输出几个 js 文件
# webpack之output
- chunkFileName:当文件时import动态模式引入的会单独打包成一个文件,文件名是个随机数,可以借助这里进行配置
- filename:文件名,可以借助一些变量拼接
- path:文件打包路径,需要是个绝对路径,借助path模块
静态资源最终访问路径 = output.publicPath + 资源loader或插件等配置路径,默认publicPath=''- assetModuleFilename:当使用asset去解析文件时,如果没有配置路径,会走这个地方的地址。配置的话走自己的路径
output: {
// chunkFilename: '[name].[chunkhash:8].js',//非入口文件的其他文件打包后命名
filename:'[name].js',
path:path.resolve(__dirname,'zip'),
//publicPath:XXX
//一般情况下是用不到的,只有在生产环境中需要用到,
//在上线的时候需要给项目中的静态资源统一配置资源前缀,代表客户端访问的上线资源地址。
}
output.publicPath = '/dist/'
// image
options: {
name: 'img/[name].[ext]?[hash]'
}
// 最终图片的访问路径为
output.publicPath + 'img/[name].[ext]?[hash]' = '/dist/img/[name].[ext]?[hash]'
// js output.filename
output: {
filename: '[name].js'
}
// 最终js的访问路径为
output.publicPath + '[name].js' = '/dist/[name].js'
// extract-text-webpack-plugin css
new ExtractTextPlugin({
filename: 'style.[chunkhash].css'
})
// 最终css的访问路径为
output.publicPath + 'style.[chunkhash].css' = '/dist/style.[chunkhash].css'
| 模板 | 描述 |
|---|---|
| [hash] | 模块标识符(module identifier)的 hash |
| [chunkhash] | chunk 内容的 hash |
| [name] | 模块名称 |
| [id] | 模块标识符(module identifier) |
| [query] | 模块的 query,例如,文件名 ? 后面的字符串 |
output: {
// publicPath: "/assets/",
chunkFilename: '[name].xxx.js', //非入口文件的其他文件打包后命名,比如动态import导入的文件
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
assetModuleFilename: "img/[name]_[hash:6][ext]"//[ext]这里包括后缀的点
// library: '[name]', // 整个库向外暴露的变量名
// libraryTarget: 'window' // 变量名添加到哪个上 browser
// libraryTarget: 'global' // 变量名添加到哪个上 node
// libraryTarget: 'commonjs'
}
# import 动态导入实现按需加载
- import 'xxx' 为静态导入,需要书写在顶级作用域中,否则会报错;静态导入的资源会在页面打开时一同加载
- import ('xxx') 为动态导入,可书写在任意作用域中;动态导入可在页面满足一定条件后进行资源加载,避免资源浪费
- 动态导入存在兼容问题,可引入@babel/plugin-syntax-dynamic-import 进行兼容
//webpackChunkName就是打包后的的[name],如果简单的import('aaa')的导入,那么[name]就是一串数字
setTimeout(()=>{
import( /* webpackChunkName: "ling" */ './ling').then((res) => {
console.log(res)
console.log(res.default())
})
},1000)
console.log("hello main");
// 再点按钮之前,就不会去加载,减少请求和打包体积
document.getElementById("btn").onclick = function () {
// 动态导入 --> 实现按需加载
// 即使只被引用了一次,也会代码分割
import("./math.js").then(({ sum }) => {
alert(sum(1, 2, 3, 4, 5));
});
};
document.getElementById("btn").onclick = function () {
// eslint不能识别动态导入需要,需要额外追加配置
// webpack魔法命名:
// 1. webpackChunkName如果两个文件重复,那么会打包到一个文件中
// 2. 如果打包的文件没有加webpack魔法命名,那么格式前缀是数字不是webpackChunkName[mathtg.chunk.bbee906e61.js]=>[1321.chunck.bbee906e61.js]
import(/* webpackChunkName: "mathtg", webpackPrefetch: true */ "./js/mathgg").then(({ mul }) => {
console.log(mul(3, 3));
});
import(/* webpackChunkName: "mathtg1", webpackPrefetch: true */ "./js/test").then(res => {
console.log(res);
});
};
如果eslint不能识别import,eslint文件需要配置
module.exports = {
// 继承 Eslint 规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
parserOptions: {
ecmaVersion: 6, // es6
sourceType: "module", // es module
},
rules: {
"no-var": 2, // 不能使用 var 定义变量
},
plugins: ["import"], // 解决动态导入import语法报错问题 --> 实际使用eslint-plugin-import的规则解决的
};
如果对返回的chunk名字需要修改整体结构,可以在output中配置chunkName进行修改。