使用__webpack_public_path__根据js路径动态拼接图片路径

1,228 阅读3分钟

背景

最近在开发组件构建功能,将vue组件构建为独立的js文件,用于被其他页面引用加载。

但是存在一个问题,html引用的图片路径正常来说要么是相对路径,要么是完整的绝对路径。

但是相对路径相对的是加载js的html页面,与js引用的图片资源路径毫无关系。又不能在构建之前决定加载js的publicPath前缀路径。

那么怎样实现js文件在任何地方加载,同时js相对路径的图片也被正常加载,是一个问题。

组件目录结构

├─dist 
│ ├─Card-demo // 组件
│ │ ├─0.0.1 // 组件版本
│ │ │ ├─index.js // 组件js
│ │ │ ├─static
│ │ │ │ ├─icon.xxx.png

观察vue-cli

在之前的开发过程中,发现使用vue-cli的构建lib库的时候,发现无论在哪个页面加载js库,图片都能正常加载。而且html加载的图片居然都是完整路径,并且工程没有处理过publicPath公共资源路径。

image.png

非常好奇,查看一下vue-cli构建代码是怎么构建的。

vue-cli构建lib库使用的是vue-cli-service build --target lib xxx命令。

构建代码在@vue\cli-service\lib\commands\build\resolveLibConfig.js位置,发现一段关键注释:

rawConfig.output = Object.assign({
  library: libName,
  libraryExport: isVueEntry ? 'default' : undefined,
  libraryTarget: format,
  // preserve UDM header from webpack 3 until webpack provides either
  // libraryTarget: 'esm' or target: 'universal'
  // https://github.com/webpack/webpack/issues/6522
  // https://github.com/webpack/webpack/issues/6525
  globalObject: `(typeof self !== 'undefined' ? self : this)`
}, rawConfig.output, {
  filename: `${entryName}.js`,
  chunkFilename: `${entryName}.[name].js`,
  // use dynamic publicPath so this can be deployed anywhere
  // the actual path will be determined at runtime by checking
  // document.currentScript.src.
  publicPath: ''
})

image.png

意思为使用动态publicPath,这样就可以在任何地方部署。实际的路径将在运行时通过检查确定。

同时断点通过vue-cli的lib命令构建的库,图片生成路径逻辑,发现是根据图片路径前缀和图片路径拼接的完整地址。

image.png

image.png

image.png

那么肯定也是通过路径前缀 + 图片地址拼接出来的完整地址。关键就在图片路径前缀怎么确定的(肯定不是html页面的路径前缀哈)。

真相大白

通过浏览器访问构建后的lib库页面,查询这个__webpack_require_.p关键字,发现是通过正则匹配相关内容后进行的赋值操作。

image.png

根据正则条件,在GitHub vue-cli源码中查找关键字,发现源码如下:

文件位置@vue\cli-service\lib\commands\build\setPublicPath.js

image.png

经过搜索,这段代码用于js文件在加载过程中,js读取到自身js的路径,赋值给__webpack_public_path__

__webpack_public_path__是webpack官方提供的自由变量

image.png

总结

所以真相就是js库文件在加载时,获取到了自身的js路径,赋值给自由变量。然后在图片资源路径生成时,路径读取的自由变量路径+图片资源路径自动拼接成了完整的图片地址。

后续我们在组件入口统一新增了这段赋值__webpack_public_path__,验证后确实实现了在任何位置引用js组件,相对js组件文件位置的图片资源都正常加载。