当模板包含自定义标签时,将自定义加载器添加到 vue-loader 会中断

问题描述

我有一个如下所示的 vue2 组件:

<template>
  <p>Hello world</p>
</template>

<script>
export default { name: 'Example' };
</script>

<docs>
Some documentation...
</docs>

我还想为我的 vue 文件使用一个额外的加载器,所以我的 webpack 配置看起来像这样:

module.exports = {
  module: {
    rules: [{
      test: /\.vue$/,use: [{
        loader: 'vue-loader',},{
        loader: path.resolve(__dirname,'Customloader.js'),}],};

// Customloader.js
module.exports = function(source) {
  return source;
}

运行 webpack bundle 会抛出一个错误,指出它缺少 <docs> 块的加载器,即使 Customloader 返回源代码不变。类似的东西:

Error in path/to/component.vue?vue&type=custom&index=0&blockType=docs
Module parse Failed: Unexpected token
File was processed with these loaders:
* ./node_modules/vue-loader/lib.index.js
* ./Customloader.js
You may need an additional loader to handle the result of these loaders.

删除其中一个

谁能告诉我这是什么问题?

解决方法

在深入研究 vue-loader 的源代码后,我自己找到了答案。从广义上讲,vue-loader 检查是否存在另一个用于 vue 文件的加载器。如果没有其他加载器,则它会丢弃自定义块的内容。否则,它将返回内容,期望其他加载程序知道如何处理它。这就是为什么添加另一个加载程序,即使是一个什么都不做的加载程序,也会导致构建失败。

如果您想更好地了解发生了什么,请查看 vue-loader 源代码,特别是:

要了解如何解决这个问题,您必须首先了解 vue-loader 是如何解析模板的。它用导入语句和内联加载器链替换每个块。所以这个

 fs.readFile(TOKEN_PATH,(err,token) => {
    if (err) return getNewToken(oAuth2Client,callback);
    oAuth2Client.setCredentials(JSON.parse(token));
    callback(oAuth2Client);
  });

fs.readFile('credentials.json',content) => {
  if (err) return console.log('Error loading client secret file:',err);
  // Authorize a client with credentials,then call the Google Sheets API.
  authorize(JSON.parse(content),listMajors);
});

变成这样

<template>
  <!-- ... -->
</template>

<script>
// ...
</script>

<docs>
// ...
</docs>

因此,本质上,自定义加载器将为每个 import render from 'custom-loader!vue-loader!source.vue?vue&type=template' import script from 'custom-loader!vue-loader!source.vue?vue&type=script' import 'custom-loader!vue-loader!source.vue?vue&type=custom&blockType=docs' 文件调用多次。第一次通过,然后对每个扩展的块再一次。

我的解决方法是检查加载程序中的 .vue。如果它指向一个自定义块,我只返回一个空模板。像这样:

resourceQuery

重要的是您返回 vue-loader(使用 vue 模板编译器)能够解析的内容。因此,// CustomLoader.js module.exports = function(source) { if (this.resourceQuery.includes('type=custom')) { return '<custom></custom>'; } return source; } 标记而不是空字符串。