解决路径问题
问题复现
在使用 file-loader 或 url-loader 时,可能会遇到一个非常有趣的问题
比如,通过 webpack 打包的目录结构如下:
yaml
dist
|—— img
|—— a.png #file-loader生成的文件
|—— scripts
|—— main.js #export default "img/a.png"
|—— html
|—— index.html #<script src="../scripts/main.js" ></script>
我们看下 index.js 做了什么操作:
js
import imgPath from "./assets/img/webpack.png";
console.log(imgPath);
if (Math.random() < 0.8) {
const img = document.createElement("img");
img.src = imgPath;
document.body.appendChild(img);
}
执行:
sh
pnpm run dev
我们发现,图片无法正确的显示,这是为什么呢?
问题分析
我们根据目录结构可知:
js
//js的运行路径是
localhost: 8000 / html / index.html;
//而我们看我们的图片的路径是:
imgs / webpack.png; //这是一个相对路径,会在当前文件夹下找imgs文件夹下的webpack.png,肯定是找不到的
//服务器找寻的真实路径:显然是多了一个/html,当然找不到了
localhost: 8000 / html / imgs / webpack.png;
//我们期待的图片地址是
localhost / imgs / webpack.png;
这种问题发生的根本原因:模块中的路径来自于某个 loader 或 plugin,当产生路径时,loader 或 plugin 只有相对于 dist 目录的路径,并不知道该路径将在哪个资源中使用,从而无法确定最终正确的路径
问题解决
面对这种情况,需要依靠 webpack 的配置 publicPath 解决
publicPath:配置公共资源路径。
该配置项本质上就是一个字符串,当配置了 publicPath 后,引用资源的路径就会在 webpack 打包的时候,将 publicPath 拼接到最开始的位置
webpack.config.js
js
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
mode: "development",
devtool: "source-map",
devServer: {
open: true,
port: 8000,
openPage: "html/index.html", //指定开发服务器打开的页面
},
entry: {
index: "./src/index.js",
},
output: {
filename: "scripts/[name]-[chunkhash:5].js", //使用相对路径,dist文件夹下生成scripts文件夹
publicPath: "/", //+++配置静态资源引用路径,一般为'/',这样webpack打包出的js中,资源路径就会加上这个配置的字符串,然后服务器就会去找公共路径下的静态资源
},
//使用file-loader
module: {
rules: [
{
test: /\.(png)|(gif)|(jpg)$/,
use: [
{
loader: "file-loader",
options: {
name: "imgs/[name].[hash:5].[ext]",
},
},
],
},
],
},
//
plugins: [
new CleanWebpackPlugin(),
/*默认会在 dist 下生成 index.html,
配置filename之后,会多出一个文件夹
这个时候,就需要只当devServer中的openPage路径了。
*/
new HtmlWebpackPlugin({
template: "./public/index.html",
filename: "html/index.html", //相对路径,dist下生成
}),
// new CopyPlugin([{ from: "./public", to: "./" }]),
],
};
打包出来的 dist/index.fs455.js
js
//片段,导入图片的打包后的结果
---
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
{
/***/ "./src/assets/img/webpack.png": function (
module,
__webpack_exports__,
__webpack_require__
) {
"use strict";
__webpack_require__.r(__webpack_exports__);
//可以看到此处加上了__webpack_require__.p
__webpack_exports__["default"] =
__webpack_require__.p + "imgs/webpack.ba6ae.png";
}
---
扩展
我们有个疑问,为什么publikcPath
一般为/
是因为我们在部署的时候,一般会将我们的前端资源部署在服务器的根目录下
js
//http://duyi.com/imgs/webpack.png
这就是会在服务器的根目录下找imgs文件夹下的webpack.png
//如果我们部署在了 http://duyi.com/website/imgs/webpack.png
那就代表,我们找的资源就部署在了服务器的website下,那么我们就需要将publicPath配置为"/website"
有些 loader 会提供 publicPath 配置项,loader 提供了的话,就与 webpack 的 publicPath 无关了,请注意这一点即可