前置知识
node 环境下 "./" 代表的意思:
- 模块化代码中,比如 require("./") ,表示当前 js 文件所在的目录。
- 在路径处理中, "./" 表示 node 运行目录。
- __dirname:所有情况下,都表示当前运行的 js 文件 所在的目录,它是一个绝对路径。
node 中的 path.resolve() 用法:
var path = require("path") // 导出一个对象
var result = path.resolve(__dirname,"src")
console.log(result) // 当前js文件所在目录的src文件夹
一、入口和出口
出口:这里的出口是针对资源列表的文件名或路径的配置。出口通过 output 进行配置。
入口:入口真正配置的是 chunk 。入口通过 entry 进行配置。
1.出口的静态规则
出口文件配置常用属性有 filename 和 path :
- filename :配置的合并的 js 文件的规则。
- path :表示资源放置的文件夹路径,必须是一个绝对路径,默认为 dist 。
webpack.config.js :
// 该对象提供了大量路径处理的函数
var path = require("path");
module.exports = {
mode: "development", // 打包环境,可以不写
entry: "./src/index.js", // 入口文件
output: {
filename: "scripts/main.js", // 配置的合并的js文件的规则,也可以写成子文件夹形式,例:"scripts/main.js",生成的文件就存放在target/scripts目录下
path: path.resolve(__dirname, "target"), // 表示资源放置的文件夹路径,必须配置一个绝对路径,默认是dist
},
devtool: "source-map", // 默认为eval,配置为eval时,浏览器报错提醒在源代码中
watch: true, // 监听文件变化,自动打包
};
打包后生成的项目目录:
2.入口文件配置
规则:
- name : chunkname 。
- hash :总的资源 hash ,通常用于解决缓存问题。浏览器访问 js 文件有缓存,再次运行时不会重新访问,导致代码没有及时更新,所以要用 hash 作为文件名。
- chunkhash :使用 chunkhash 。
- id :使用 chunkid ,不推荐,开发环境是名字,生产环境是数字。
默认情况下,入口配置如下, main 为 chunk 的名称,后面是 chunk 对应的是入口模块:
entry: {
main: "./src/index.js" // 属性名:chunk的名称;属性值:入口模块(启动模块)
},
name :配置多个入口文件时,需要将出口 js 文件进行配置,用 chunkname 代替出口文件名称。
var path = require("path");
module.exports = {
mode: "development", // 打包环境,可以不写
entry: {
main: "./src/index.js", // 属性名:chunk的名称,属性值:入口模块(启动模块)
a: "./src/a.js",
},
output: {
filename: "[name].js", // 配置的合并的js文件的规则
path: path.resolve(__dirname, "target"), // 表示资源放置的文件夹路径
},
devtool: "source-map",
watch: true,
};
打包后生成的项目目录:
hash :
当文件内容发生改变会生成新的 hash 。
var path = require("path");
module.exports = {
mode: "development", // 打包环境,可以不写
entry: {
main: "./src/index.js", // 属性名:chunk的名称,属性值:入口模块(启动模块)
a: "./src/a.js",
},
output: {
filename: "[name].[hash].js", // 配置的合并的js文件的规则,hash:5 代表取5位
path: path.resolve(__dirname, "target"),
},
};
打包后生成的项目目录:
chunkhash :
使用 chunkhash 作为出口文件规则的好处是,当文件内容发生改变时,只会影响该 chunk 的出口,生成新的 js 文件,不会影响其他 chunk 。
var path = require("path");
module.exports = {
mode: "development", // 打包环境,可以不写
entry: {
main: "./src/index.js", // 属性名:chunk的名称,属性值:入口模块(启动模块)
a: "./src/a.js",
},
output: {
filename: "[name].[chunkhash:5].js", // 配置的合并的js文件的规则
path: path.resolve(__dirname, "target"),
},
};
打包后生成的项目目录:
当 a.js 文件内容发生改变时,只会生成新的文件替换 a.200558.js 文件, main.db224.js 文件不会改变。
当一个 chunk 配置两个启动模块时,会按顺序先后运行这两个模块。
var path = require("path");
module.exports = {
mode: "development", // 打包环境,可以不写
entry: {
main: "./src/index.js", // 属性名:chunk的名称,属性值:入口模块(启动模块)
a: ["./src/a.js", "./src/index.js"], // 启动模块有两个
},
output: {
filename: "[name].[chunkhash:5].js", // 配置的合并的js文件的规则
path: path.resolve(__dirname, "target"),
},
};
二、最佳实践
场景一:一个页面一个 js
pageA ==> JS
pageB ==> JS
pageC ==> JS
源码结构:
|—— src
|—— pageA 页面A的代码目录
|—— index.js 页面A的启动模块
|—— ...
|—— pageB 页面B的代码目录
|—— index.js 页面B的启动模块
|—— ...
|—— pageC 页面C的代码目录
|—— main1.js 页面C的启动模块1 例如:主功能
|—— main2.js 页面C的启动模块2 例如:实现访问统计的额外功能
|—— ...
|—— common 公共代码目录
|—— ...
webpack 配置:
module.exports = {
entry:{
pageA: "./src/pageA/index.js",
pageB: "./src/pageB/index.js",
pageC: ["./src/pageC/main1.js", "./src/pageC/main2.js"]
},
output:{
filename:"[name].[chunkhash:5].js"
}
}
这种方式适用于页面之间的功能差异巨大、公共代码较少的情况,这种情况下打包出来的最终代码不会有太多重复。
场景二:一个页面多个 js
pageA ==> JS1
pageA ==> JS2
pageB ==> JS1
pageB ==> JS3
源码结构:
|—— src
|—— pageA 页面A的代码目录
|—— index.js 页面A的启动模块
|—— ...
|—— pageB 页面B的代码目录
|—— index.js 页面B的启动模块
|—— ...
|—— statistics 用于统计访问人数功能目录
|—— index.js 启动模块
|—— ...
|—— common 公共代码目录
|—— ...
webpack 配置:
module.exports = {
entry:{
pageA: "./src/pageA/index.js",
pageB: "./src/pageB/index.js",
statistics: "./src/statistics/index.js"
},
output:{
filename:"[name].[chunkhash:5].js"
}
}
这种方式适用于页面之间有一些独立、相同的功能,专门使用一个 chunk 抽离这部分 JS 有利于浏览器更好的缓存这部分内容。
场景三:单页应用
所谓单页应用,是指整个网站(或网站的某一个功能块)只有一个页面,页面中的内容全部靠 JS 创建和控制。 vue 和 react 都是实现单页应用的利器。
源码结构:
|—— src
|—— subFunc 子功能目录
|—— ...
|—— subFunc 子功能目录
|—— ...
|—— common 公共代码目录
|—— ...
|—— index.js
webpack 配置:
module.exports = {
entry: "./src/index.js",
output:{
filename:"index.[hash:5].js"
}
}