webpack的常用基本配置我们可能已经耳熟能详,比如
input
,output
,module
,plugins
,devServer
的配置等等。而在这些基本配置中,其实还有一些细节参数,它可以帮助我们更好的定制化打包的目录结构,但它可能并不是那么好理解,比如publicPath。
webpack官网这么解释:publicPath
配置项在很多场景下都非常有用,它允许你给你的应用中的所有静态资源指定一个基本路径。
The publicPath configuration option can be quite useful in a variety of scenarios. It allows you to specify the base path for all the assets within your application.
有些抽象,我总结了下,它大概做的事情就是:可以帮我们处理资源引用的url路径问题:为生成的资源自动添加特定路径前缀。
什么时候需要使用publicPath
?
1. 打包出来的文件有特定目录结构划分时
webpack打包出来的文件,默认都统一放在output
配置的path
路径下,项目稍大一点,这个目录中的文件就比较杂乱了,我们可能会希望给这些文件进行归类。当然我们可以粗暴一点通过filename
来指定一个子目录。但是,如果在这这个子目录中,文件还有层级,就需要配置相应 plugin 或者 loader 的 publicPath
了。
例如file-loader
,我们可以配置它的outputPath
自定义生成文件存放在output.path
的哪个子目录,并且配置它的 publicPath
指定资源路径前缀:
在file-loader
中publicPath
的值可以是string
和function
1
2
3
4
5
6
7
8
9
10
11
12module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
outputPath: 'media', // string
publicPath: 'media', // string
}
}
]
}
这样,编译打包后的图片资源就会放在dist/media
目录下(假设你设置的output path为dist),并且所有引用到图片的资源路径都会自动加上前缀 media/
。
如果想对不同的图片添加不同的路径前缀,可以使用函数来定义publicPath
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
publicPath: (url, resourcePath, context) => {
// `resourcePath` 是这个资源的本地绝对路径
// `context` 是存放这个资源的目录,或者是`context`配置项的值
// 想获取相对路径可以这样:
// const relativePath = path.relative(context, resourcePath);
// 将符合下面条件的png图片url添加前缀 `other_public_path`
if (/my-custom-image\.png/.test(resourcePath)) {
return `other_public_path/${url}`;
}
// 将符合下面条件的图片url添加前缀 `image_output_path`
if (/images/.test(context)) {
return `image_output_path/${url}`;
}
// 其他图片url添加前缀 `public_path`
return `public_path/${url}`;
}
}
}
]
}
这样编译打包出来的图片url,就会根据你的设置,分别加上 other_public_path
、image_output_path
和public_path
前缀了(当然这几个目录的名称你自己来定),是不是很不错?
2. 生产模式要求index首页不在根目录下
例如在某些生产模式下,要求产出的文件目录类似这样:1
2
3
4
5|--assets/
| |--index.js
| |--vendor.js
|--page/
|--index.html
那么可以这么配置webpack:1
2
3
4
5
6
7
8
9
10
11
12// webpack.prod.js file
output: {
filename: 'assets/[name].js',
path: resolve(__dirname, '../', 'dist'),
publicPath: '../' // 相对HTML页面的路径
},
plugins: [
new HtmlWebpackPlugin({
template: '../public/index.html',
filename: 'pages/index.html'
})
],
编译后,在index.html
中index.js
的引用就会变成这样:1
<script src=../assets/index.js></script>
在
output
中publicPath
的值可以是以下几种:
1
2
3
4
5
6
7
8
9
10
11
12 module.exports = {
//...
output: {
// 以下几种之一
publicPath: 'https://cdn.example.com/assets/', // CDN (一定是HTTPS)
publicPath: '//cdn.example.com/assets/', // CDN (HTTPS协议)
publicPath: '/assets/', // 相对服务端跟目录
publicPath: 'assets/', // 相对 HTML 页面文件
publicPath: '../assets/', // 相对 HTML 页面文件
publicPath: '', // 相对 HTML 页面文件 (与HTML同一目录)
}
};
3. 生产模式下的静态资源在CDN上托管时
例如在某些生产模式下,静态文件都由www.xx.com/assets
来托管
那么可以在 webpack 中这么配置 publicPath:1
2
3
4
5
6// webpack.prod.js file
output: {
filename: 'assets/[name].js',
path: resolve(__dirname, '../', 'dist'),
publicPath: 'https://www.xx.com/assets' // CDN URL
},
编译后,在 index.html 中 index.js 的引用就会变成这样:1
<script src=https://www.xx.com/assets/index.js></script>
其他
在devServer
中也有publicPath
配置,默认它是获取output
的publicPath
的值。
要提一下,webpack-dev-server生成的文件是不会放在硬盘的,而是在内存中,所以看不到。只有在请求资源的时候,可以证明文件的存在。。。1
2
3devServer {
publicPath: '/assets/'
}
一定要在string的前后都放上
/
。
需要注意的是,devServer
中还有一个叫做contentBase
的参数,这个参数如果配置的不好,跟publicPath
一搭配,很可能会导致请求不到页面(我也是被这个坑了很久)。这个地方如果出问题,基本上原因在于contentBase
设置的路径范围太小了,去掉contentBase
配置,或者给它配置多个路径,把输出目录包含进来,就可以解决问题。
1 | devServer { |
–
GOOD LUCK!
参考:
https://webpack.js.org/guides/public-path/
https://www.npmjs.com/package/file-loader