webpack 功能强大,现目前还是前端使用最多的 "静态模块打包工具",当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。
在上一篇文章中,介绍到了webpack打包原理,知道了为什么要使用webpack打包,以及他的优缺点和他的进阶版工具Vite。
想要使用好webpack,必须明白其运行原理、核心配置、在具体项目中运用场景
等等,下面介绍核心配置
。
本文对webpack中的
入口起点和出口文件
进行介绍,其他配置项,如:loader、plugin、moudules、热替换等等,下面的文章陆续做介绍。
一、入口起点(entry points)
入口就是打包的入口文件(大多时候是main.js或者、src/index.js文件)
单个入口
语法:entry: string | [string]
js
// webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js',
};
上面的entry
属性的单个入口语法,是以下面形式的简写:
js
module.exports = {
entry: {
main: './path/to/my/entry/file.js',
},
};
多个入口文件
多个入口文件可以是数组或者对象形式,传递给entry属性
数组形式
css
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],
output: {
filename: 'bundle.js',
},
};
这样创建,是想一次性注入多个依赖文件,并且将他们的依赖关系绘制成一个依赖图
。
对象形式
js
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js',
},
};
这样是创建了,三个独立分离的依赖图
。
对象语法非常繁琐
,但是,也是定义入口文件的最可扩展的方式,可以对每个依赖图进行不同配置
。
可以使用如下属性:
dependOn
: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。filename
: 指定要输出的文件名称。import
: 启动时需加载的模块。library
: 指定 library 选项,为当前 entry 构建一个 library。runtime
: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为false
以避免一个新的运行时 chunk。publicPath
: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。请查看 output.publicPath。
属性使用复杂,举个例子:
js
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: {
dependOn: 'pageOne', // pageTwo 依赖于 pageOne,也就是说 pageOne 必须加载在前面
import:'./src/pageTwo/index.js', // 项目启动就加载
},
pageThree: './src/pageThree/index.js',
},
};
注意:
1、
runtime
和dependOn
不应在同一个入口上同时使用,因为设置了runtime
属性,就会从新运行一个依赖图,但是dependOn
属性又表示你是依赖于其他入口文件的,不能单独创建,所有就会出现错误。2、
runtime
不能指向已存在的入口文件,因为已经存在的入口文件,已经创建了一个依赖图,runtime
属性又重新创建了一个一样的,所有就会出现错误。3、
dependOn
不能相互引用,因为依赖关系是单一的,不能'你是他爸爸,他又是你爸爸'
下面是三种错误的,错误写法:
js
// 1、`runtime` 和 `dependOn` 不应在同一个入口上同时使用
module.exports = {
entry: {
a2: './a',
b2: {
runtime: 'x2',
dependOn: 'a2',
import: './b',
},
},
};
// 2、`runtime` 不能指向已存在的入口文件
module.exports = {
entry: {
a1: './a',
b1: {
runtime: 'a1',
import: './b',
},
},
};
// 3、`dependOn` 不能相互引用
module.exports = {
entry: {
a3: {
import: './a',
dependOn: 'b3',
},
b3: {
import: './b',
dependOn: 'a3',
},
},
};
总之对象语法,在不清楚使用属性的作用前,不要使用,一般项目中使用十分少。
想知道 entry 的高级用法,和使用规则,可以前往官方配置
2、输出(output)
将打包的文件,存放在硬盘的位置。注意,即使可以存在多个 entry
起点,但只能指定一个 output
配置。
单个出口文件
js
const path = require('path'); // 引入 path 模块
module.exports = {
entry:'./scr/mian.js',
output:{
filename:"build.js", // 打包的文件名
path:path.resolve(__dirname,'dist') // 打包后,存储的位置和文件名
}
}
多个出口文件
数组形式出口文件
js
const path = require('path');
module.exports = {
entry:['./src/main.js','./src/bus.js'],
output:{
filename:"[name].js",
path:path.resolve(__dirname,'dist')
}
}
// 这种写法,有几个入口文件就有几个出口文件
对象形式出口文件
js
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js',
},
output: {
filename: '[name].js',
path: __dirname + '/dist',
},
};
// 写入到硬盘:./dist/app.js, ./dist/search.js
高级用法
高级用法的配置项,多达50多个属性,使用的方式非常多,可以前往官方output配置
例如:当将资源托管到 CDN 时,需要按需加载或加载外部资源(如图片、文件等)
js
const path = require('path');
module.exports = {
//...
output: {
path: path.resolve(__dirname, 'public/assets'),
publicPath: 'https://cdn.example.com/assets/',
},
};
在编译时(compile time)不知道输出文件的 publicPath
属性的情况下,可以留空,然后在入口文件(entry file)处使用自由变量(free variable) __webpack_public_path__
,以便在运行时(runtime)进行动态设置。
js
__webpack_public_path__ = myRuntimePublicPath;
// 应用程序入口的其他部分
实际项目中运用
在实际项目中,写法有些不一样,因为都是在框架中完成开发,所以要遵循框架的语法,但是思想相同
js
// vue.config.js
const path = require('path');
function resolve(dir) { // 地址格式化
return path.join(__dirname, dir)
}
console.log(process.env.NODE_ENV, "当前的环境")
module.exports = {
publicPath: '/', // 指定构建后的资源的根路径,默认为"/"
// 或者
publicPath: process.env.NODE_ENV === "production" ? "./" : "/",
outputDir: 'dist', // 指定构建后的资源的输出目录,默认为"dist"
chainWebpack: (config) => {
config.entryPoints.clear() // 会把默认的入口清空
config.entry('main').add('./src/main.js'); // 入口文件
}
}
在vue项目中,配置写在vue.config.js文件中,项目运行、打包,也是使用Vue CLI脚手架进行(chainWebpack
就是 Vue CLI 3.x 及以上版本中提供的一个配置项)
package.json文件中的运行命令