你真的知道publicPath的用处吗?无论是官方文档,还是水友的解释都很难让豁然开朗,比如:
对于按需加载(on-demand-load)或加载外部资源(external resources)(如图片、文件等)来说,output.publicPath 是很重要的选项。如果指定了一个错误的值,则在加载这些资源时会收到 404 错误。
此选项指定在浏览器中所引用的「此输出目录对应的公开 URL」。相对 URL(relative URL) 会被相对于 HTML 页面(或 <base> 标签)解析。相对于服务的 URL(Server-relative URL),相对于协议的 URL(protocol-relative URL) 或绝对 URL(absolute URL) 也可是可能用到的,或者有时必须用到,例如:当将资源托管到 CDN 时。
实验是检验用法的最好途径,于是设置目录结构如下:
src
|---index.html
|---index.js
|---asssets
|----1.jpg
- index.html使用<script src="./dist/bundle.js"/>的方式引入打包后的脚本。
- index.js使用require('./assets/1.jpg')的方式引入了图片
- webpack.config.js的配置如下:
entry:"./index.js",
output:{
filename:"bundle.js",
path:path.resolve(__dirname,"dist"),
},
devServer:{
},
目的是将脚本打包到一个统一的dist文件夹下。
使用webpack-dev-server重新打包并打开index.html时,报错如下:
http://localhost:8080/dist/bundle.js net::ERR_ABORTED
为什么找不到呢?
- webpack-dev-server使用的是内存中的打包文件,并不是webpack命令打包后的路径。(上面我没有使用webpack命令打包哦。)
- webpack-dev-server在不设置publicPath的情况下,将默认输出bundle.js到根目录。不信,你输入localhost:8080/bundle.js就能看到这个Js。
- 报错是因为,输出的bundle.js在根目录,而html却要去加载dist目录下的,所以找不到(上文:index.html使用<script src="./dist/bundle.js"/>的方式引入打包后的脚本)。
这时你需要在devServer中添加publicPath属性:
publicPath: "/dist/"
重新使用webpack-dev-server打包,并打开index.html你会发现,找到了bundle.js。但是仍旧提示找不到图片
http://localhost:8080/c3bbc15b8d6be7ec744c8a32670d7f6c.png 404 (Not Found)
所以,此时devServer.pulicPath属性的含义可以这么理解:
- 将你的打包文件输出到哪个路径下,该路径是在内存里(你看不到但存在),相对于加载bundle.js的index.html页面或web服务根目录的哪个路径下。(本示例就相对web服务根目录,因为是以"/"开头)
- 此时webpack.config.js中,output.path是可以删除的。因为这个路径是输出到硬盘上的物理路径。与webpack-dev-server完全无关。
可为什么找不到图片呢?先回味一下官方原文
对于按需加载(on-demand-load)或加载外部资源(external resources)(如图片、文件等)来说,output.publicPath 是很重要的选项。如果指定了一个错误的值,则在加载这些资源时会收到 404 错误。
也就是说:如果你require了一些资源或直接引用了网络上的资源,这些资源里包含uri属性(如css中设置img:url('./1.jpg')),就要使用就这个属性,否则会找不到文件。(如果没有使用uri资源,那么这个属性没什么用)。
说人话---这个属性就是让webpack在打包时才能根据配置动态修改uri中的相对值的;你不配置,webpack打包后的bundle.js中引用的url不对。
于是再去配置output下的publicPath,将其修改为
output:{
filename:"bundle.js",
path:path.resolve(__dirname,"dist"),
publicPath: "/dist/"
},
重新执行webpack-dev-server,打开index.html发现一切正常!
后来尝试,不配置webserver.publicPath,而只配置output中的publicPath且修改为:
publicPath: "/dist/"
重新执行webpack-dev-server,打开index.html发现一切正常!
难道我对webserver.publicPath的理解有错?
比较了加与不加时,控制台打印出的日志才明白:
- 当你不配置devServer下的publicPath时,其会默认将包打到output.publicPath的路径下。
- 当你配置了devServer下的publicPath时,才其会将包打开你指定的路径下。
个人理解:
- output.path:硬盘上的路径,也就是你打算把文件打包到你的哪个目录,也就是各个牛人说的绝对路径!与发布时的路径完全无关。
- output.publicPath:主要用来转换url中的相对路径的。如果你引用到包含url的资源,一定要配置output.publicPath。配置了此项,webpack在打包时才能根据配置动态修改uri中的相对值。
- devserver.publicPath:可以理解为服务或模块的发布路径!注意:该值后面都要有"/"!本示例的index.html用了dist目录下的bundle.js,所以我们需要将模块发布到dist目录下就正确了。
4.output.path对应的是硬盘上路径,output.publicPath对应的是你这打好的包将来放在web服务器上后,使用www.xxx.xx/xxx/xx形式访问时对应的url.本示例中因为我引用的是域名下/dist目录中的js。所以其对应的publicPath就应该为/dist/ - 如果你使用webstorm,千万不要在webpack打包后,使用其自带的端口为63342的默认web服务器打开index.html。这个默认的web服务器会以你的工程目录为根目录,而不像webpack-dev-server是以配置文件所在目录为根目录。