理解 Webpack3 路径配置项

原创
前端路迹
2018-3-14 12:46
编辑于 2022-6-17 15:24

Webpack 中有很多涉及路径参数配置,若不知其所以然,很容易混淆出错。本文尽可能的汇集了 Webpack 中涉及路径的配置,力争深入浅出。

context

context 是 Webpack 编译时的基础目录,入口起点(entry)会相对此目录进行查找。

默认值为当前目录,Webpack 设置 context 默认值源码:

this.set("context", process.cwd());

process.cwd()即 Webpack 运行所在的目录(可以等同 package.json 所在目录)。

context 需配置为绝对路径,下面举例说明 context 配置对 entry 的影响。假设入口起点路径为src/web/main.js,那么 context 和 entry 可以做如下配置。

webpack-path
    |-- context
        |-- webpack.config.js
        |-- src
            |-- admin    
            |-- web
                |-- main.js

context 和 entry 的配置关系如下。

{
    context: path.resolve(__dirname, './src/'),
    entry: './web/main.js'
}
{
    context: path.resolve(__dirname, './src/web'),
    entry: './main.js'
}
{
    context: path.resolve(__dirname, './src/admin'),
    entry: '../web/main.js'
}

对于最后一个,虽然实际使用中一般不会这样配置,但可以非常充分的说明,一旦配置了 context,那么在配置 entry 的时候,就需要相对于 context 配置的路径去设置。

context 有什么实际作用?官方文档的解释是使得你的配置独立于工程目录 「This makes your configuration independent from CWD (current working directory)」。怎么理解?举个例子,在分离开发生产配置文件时候,一般把 webpack.config.js 放到 build 文件夹下,此时 entry 却不用考虑相对于 build 目录来配置,只需根据 context 的配置来设置。

!> entry 若配置为绝对路径,则和 context 没关系
output 的配置项和 context 没有关系,但是有些插件的配置项和 context 有关,后面会说明。

##output

###output.path

打包文件输出的目录,必须配置为绝对路径,默认值和 context 的默认值一样,都是process.cwd()

除了常规的配置方式,还可以在 path 中用使用 [hash] 模板,比如配置:

output: {
    path: path.resolve('./dist/[hash:8]/'),
    filename: '[name].js'
}

打包后的目录如下:

这里的 hash 值是编译过程的 hash,如果被打包进来的内容改变了,那么 hash 值也会发生改变。这个可以用于版本回滚。你也可以配置为path.resolve(./dist/${Date.now()}/)方便做持续集成等。

###ouput.publicPath

记得最开始学习 Webpack 的时候,一直没把 publiPath 理解透彻,甚至还错误的认为它和 output.path 有关联。这个配置项在很多场景是非常重要的,如果不深入理解,就不能灵活运用。

怎么快速又准确的理解 publicPath,我觉得可以用下面的这个公式来表述:

静态资源最终访问路径 = output.publicPath + 资源 loader 或插件等配置路径

举例说明:

output.publicPath = '/static/'

// 图片 url-loader 配置
{
    name: 'img/[name].[ext]'
}
// 那么图片最终的访问路径为
output.publicPath + 'img/[name].[ext]' = '/static/img/[name].[ext]'

// JS output.filename 配置
{
    filename: 'js/[name].js'
}
// 那么JS最终访问路径为 
output.publicPath + 'js/[name].js' = '/static/js/[name].js'

// CSS 
new ExtractTextPlugin("css/style.css")
// 那么最终CSS的访问路径为
output.publicPath + 'css/style.css' = '/static/css/style.css'

publicPath 默认值为空字符串,接下来看其他各种常见的 publicPath 配置的实际意义。

publicPath 设为相对路径,举例说明。

{
    context: path.resolve(__dirname, './src'),
    entry: './main.js',
    output: {
        path: path.resolve(__dirname, `./static/`),
        filename: 'js/[name].js',
        publicPath: '../static/'
    }
}

在上面的配置,publickPath 配置为相对路径,按照公式,那么 main.js 访问的路径为:

静态资源最终访问路径 = output.publicPath + 资源 loader 或插件等配置路径

main.js 访问路径 = '../static/' + 'js/main.js' = '../static/js/main.js'

如何理解最终的路径,其实它这决定了引用资源页面的路径,比如要使得 index.html 能够正确引用 main.js,那么从访问 main.js 相对路径反推,index.html 需要放在 static 目录下或者和其平级的某个文件夹下下才能正常访问。

放在 static 目录
|-- static
    |-- index.html
    |-- js
        |-- main.js 

和 static 平级的某个文件夹下
|-- static
|   |-- js
|       |-- main.js 
|
|-- page
    |-- index.html

实际开发中一般都不会使用相对路径,相对路径的直接以文件方式访问(file://),比如一些混合 APP 就用的这种方式,此时就不适合使用绝对路径了。

publicPath 设为 http 地址(http://),比如`publicPath:'http://wwww.qinshenxue.com/static/'`,适合资源托管到 CDN 的情况,比如公司的静态资源服务器等。

!> publicPath 应该以/结尾,同时其它 loader 或插件的配置不能以/开头。

##webpack-dev-server

###publicPath

上面讲过 webpack 的 publicPath,那么这里的 publicPath 和 上面的publicPath是不是一回事呢?答案是两者区别很大,首先这里的 publicPath 用于开发环境的,那这两者到底有啥区别呢?

我们知道 webpack-dev-server 打包的内容是放在内存中,通过 express 匹配请求路径,然后读取对应的资源输出。这些资源对外的根目录就是 publicPath,可以理解为和 outpu.path 的功能一样,将所有资源放在此目录下,在浏览器可以直接访问此目录下的资源。

但是这个路径仅仅只是为了提供浏览器访问打包资源的功能,Webpack 中的 loader 和插件仍然是以 ouput.publicPath 为准,这也是为什么官方推荐 publicPath 和 webpack 配置的保持一致(除了 http 地址),配置一致才能正常访问其它静态资源。

上面的解释可能还是比较生硬,还是举几个例子来说明:

本例将两处 publicPath 配置成不一样的,这样更容易对比理解。

// webpack.config.js
output: {
    path: path.resolve(`./dist/`),
    filename: 'js/[name].js',
    publicPath: '/static/'
}
// api 调用 webpack-dev-server
var webpack = require('webpack');
var webpackDevServer = require('webpack-dev-server');
var config = require("./webpack.config");
var compiler = webpack(config);
var server = new webpackDevServer(compiler, {
    hot: true,
    publicPath: '/web/'
});
server.listen(8282, "0.0.0.0")

如何查看 webpack-dev-server 所有启动后的资源访问路径呢?有个简单的方法,就是访问/webpack-dev-server,本例访问截图如下:

上面的资源可以点击查看,你会发现,资源的路径都是/web/*,所以在index.html中引入JS的路径应为/web/js/main.js,同时也能看到,style.css中的图片路径仍然为/static/img/**.png,而不是/web/。

##html-webpack-plugin

这个插件的几处配置受路径配置影响,因此需要专门说明下。

###template

template的路径是相对于 output.context,源码如下:

this.options.template = this.getFullTemplatePath(this.options.template, compiler.context);

因此 template 对应的文件需要放在 ouput.context 配置的目录下才能被识别。

###filename

filename的路径是相对于 output.path,源码如下:

this.options.filename = path.relative(compiler.options.output.path, filename);

在 webpack-dev-server 中,则相对于 webpack-dev-server 配置的 publicPath。

若 webpack-dev-server 中的 publicPath 和 ouput.publicPath 不一致,在这种配置下使用html-webpack-plugin是有如下问题:

这两个问题也反推出了最方便的配置为:

转载请注明出处。本文地址: https://www.qinshenxue.com/article/20170315092242.html
Star支持
关注 & 咨询问题