Repository: vuejs/vue-loader
Pull request #744 (2017-03-26 09:09:20)

support pre/post loaders for custom blocks
/ping @yyx990803 


Patch:
diff --git a/docs/ja/configurations/advanced.md b/docs/ja/configurations/advanced.md
index 6778fcd..6b534b9 100644
--- a/docs/ja/configurations/advanced.md
+++ b/docs/ja/configurations/advanced.md
@@ -46,7 +46,10 @@ module.exports = {
           //   postcss プラグインを使用する方が良い選択になります。
           postLoaders: {
             html: 'babel-loader'
-          }
+          },
+
+          // `excludedPreLoaders` は正規表現で設定する必要があります。
+          excludedPreLoaders: /(eslint-loader)/
         }
       }
     ]
diff --git a/docs/pt_BR/configurations/custom-blocks.md b/docs/pt_BR/configurations/custom-blocks.md
index f347058..18a23ae 100644
--- a/docs/pt_BR/configurations/custom-blocks.md
+++ b/docs/pt_BR/configurations/custom-blocks.md
@@ -2,7 +2,7 @@
 
 > Requer versão 10.2.0+
 
-Você pode definir blocos de linguagem customizados dentro de arquivos `*.vue`. O conteúdo do bloco customizado será processado ppelos carregadores especificados na opção `loaders` do objeto de configuração `vue-loader` e então requerido pelo módulo componente. A configuração é semelhante a descrita em [Configurações Avançada do Carregador](../configurations/advanced.md), exceto o uso padrão do nome da tag em vez do atributo `lang`;
+Você pode definir blocos de linguagem customizados dentro de arquivos `*.vue`. O conteúdo do bloco customizado será processado pelos carregadores especificados na opção `loaders` do objeto de configuração `vue-loader` e então requerido pelo módulo componente. A configuração é semelhante a descrita em [Configurações Avançada do Carregador](../configurations/advanced.md), exceto o uso padrão do nome da tag em vez do atributo `lang`;
 
 Se for encontrado um carregador correspondente para um bloco customizado, ele será processado. Caso contrário o bloco customizado será simplesmente ignorado. Além disso, se o carregador encontrado retornar uma função, essa função será chamada com o componente do arquivo `* .vue` como um parâmetro.
 
diff --git a/lib/loader.js b/lib/loader.js
index 42864eb..9b47464 100644
--- a/lib/loader.js
+++ b/lib/loader.js
@@ -174,7 +174,7 @@ module.exports = function (content) {
 
   function getLoaderString (type, part, index, scoped) {
     var loader = getRawLoaderString(type, part, index, scoped)
-    var lang = part.lang || defaultLang[type]
+    var lang = getLangString(type, part)
     if (preLoaders[lang]) {
       loader = loader + ensureBang(preLoaders[lang])
     }
@@ -184,6 +184,14 @@ module.exports = function (content) {
     return loader
   }
 
+  function getLangString (type, part) {
+    if (type === 'script' || type === 'template' || type === 'styles') {
+      return part.lang || defaultLang[type]
+    } else {
+      return type
+    }
+  }
+
   function getRawLoaderString (type, part, index, scoped) {
     var lang = part.lang || defaultLang[type]
     var loader = loaders[lang]
diff --git a/package.json b/package.json
index e6b095a..75001c8 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
     "extract-text-webpack-plugin": "^2.0.0-rc.0",
     "file-loader": "^0.10.0",
     "inject-loader": "^2.0.0",
+    "js-yaml": "^3.8.2",
     "jsdom": "^9.2.1",
     "marked": "^0.3.6",
     "memory-fs": "^0.4.1",


Test patch:
diff --git a/test/fixtures/custom-blocks.vue b/test/fixtures/custom-blocks.vue
new file mode 100644
index 0000000..de3f103
--- /dev/null
+++ b/test/fixtures/custom-blocks.vue
@@ -0,0 +1,15 @@
+<i18n lang="yaml">
+en:
+  hello: "hello world"
+ja:
+  hello: "こんにちは、世界"
+</i18n>
+
+<blog>## foo</blog>
+
+<template>
+  <div>
+    <h1>{{ msg }}</h1>
+    <p v-html="blog"></p>
+  </div>
+</template>
diff --git a/test/mock-loaders/blog.js b/test/mock-loaders/blog.js
new file mode 100644
index 0000000..d441233
--- /dev/null
+++ b/test/mock-loaders/blog.js
@@ -0,0 +1,8 @@
+function normalize (code) {
+  return code.split(/\r?\n/).map(function (line) { return line }).join('')
+}
+
+module.exports = function (source) {
+  var code = "module.exports = function (Component) { Component.options.__blog = '" + source + "' }"
+  return normalize(code)
+}
diff --git a/test/mock-loaders/i18n.js b/test/mock-loaders/i18n.js
new file mode 100644
index 0000000..718312e
--- /dev/null
+++ b/test/mock-loaders/i18n.js
@@ -0,0 +1,6 @@
+module.exports = function (source) {
+  var value = typeof source === 'string' ? JSON.parse(source) : source
+  var jsonString = JSON.stringify(value).replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029')
+  var code = 'module.exports = function (Component) { Component.options.__i18n = ' + JSON.stringify(jsonString) + ' }'
+  this.callback(null, code)
+}
diff --git a/test/mock-loaders/yaml.js b/test/mock-loaders/yaml.js
new file mode 100644
index 0000000..a27de0b
--- /dev/null
+++ b/test/mock-loaders/yaml.js
@@ -0,0 +1,7 @@
+var yaml = require('js-yaml')
+
+module.exports = function (source) {
+  this.cacheable && this.cacheable()
+  var res = yaml.safeLoad(source)
+  return JSON.stringify(res)
+}
diff --git a/test/test.js b/test/test.js
index 8e49f28..5e71b44 100644
--- a/test/test.js
+++ b/test/test.js
@@ -716,6 +716,32 @@ describe('vue-loader', function () {
     })
   })
 
+  it('pre/post loaders for custom blocks', done => {
+    test({
+      entry: './test/fixtures/custom-blocks.vue',
+      vue: {
+        preLoaders: {
+          i18n: require.resolve('./mock-loaders/yaml')
+        },
+        loaders: {
+          i18n: require.resolve('./mock-loaders/i18n'),
+          blog: 'marked'
+        },
+        postLoaders: {
+          blog: require.resolve('./mock-loaders/blog')
+        }
+      }
+    }, (window, module) => {
+      var vnode = mockRender(module, {
+        msg: JSON.parse(module.__i18n).en.hello,
+        blog: module.__blog
+      })
+      expect(vnode.children[0].children[0]).to.equal('hello world')
+      expect(vnode.children[2].data.domProps.innerHTML).to.equal('<h2 id="foo">foo</h2>')
+      done()
+    })
+  })
+
   it('custom compiler modules', done => {
     test({
       entry: './test/fixtures/custom-module.vue',