一、疑惑

最近在用 webpack4 做 vue 的开发环境,只不过是对 webpack-simple 进行一些可控化。

所以干脆就自己搞了,但是遇到一个问题:

webpack-simple 中,在 App.vue 的 template 中直接写的 <img src="./logo.png"> 能够直接将 logo 进行打包。

开始我不清楚这个是什么原理,因为 webpack 本身无法通过 file-loader 直接去打包 html 中的 img 标签的。

为此我去 segmenfault 提了一个问题:

二、问题解决

最终在 vue-loader 中找到的答案:

默认情况下,vue-loader 使用 css-loader 和 Vue 模版编译器自动处理样式和模版文件。在编译过程中,所有的资源路径例如 <img src="...">background: url(...)@import 会作为模块依赖。

例如,url(./image.png) 会被转换为 require('./image.png'),而

<img src="../image.png">
 将会编译为:
createElement('img', { attrs: { src: require('../image.png') }})

这是 vue-loader 的第一步,因为 img 标签是写在 template 中的(也就是 vue 文件),因此会进行编译。

而有的时候写的 img 却无法打包出来,这与 vue 的编译规则有关:

三、vue-loader 的编译规则

  • 如果路径是绝对路径,会原样保留。
  • 如果路径以 . 开头,将会被看作相对的模块依赖,并按照你的本地文件系统上的目录结构进行解析。
  • 如果路径以 ~ 开头,其后的部分将会被看作模块依赖。这意味着你可以用该特性来引用一个 node 依赖中的资源
  • (13.7.0+) 如果路径以@ 开头,也会被看作模块依赖。如果你的 webpack 配置中给 @ 配置了 alias,这就很有用了。所有 vue-cli 创建的项目都默认配置了将 @ 指向 /src。

如果 template 中的 img 标签写法如下:

<img src="assets/logo.png">

这会原样保留,因为考虑到可能使用 cdn 或者其他 url 的图片。

如果下面的写法则会正常编译:

<img src="./assets/logo.png">

编译之后,因为转换成了 require('./assets/logo.png') 这种形式,所以会通过 file-loader 进行图片打包。

logo.png