Skip to content

Commit

Permalink
feat: handle <template lang="xxx"> with loaders
Browse files Browse the repository at this point in the history
BREAKING CHANGE: <template lang="xxx"> are now handled
with webpack loaders as well.
  • Loading branch information
yyx990803 committed Mar 25, 2018
1 parent 144cc7c commit c954f32
Show file tree
Hide file tree
Showing 15 changed files with 173 additions and 17 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,50 @@ The benefit is that this same rule also applies to plain `*.less` imports from J

v15 also allows using non-serializable options for loaders, which was not possible in previous versions.

### Template Preprocessing

v14 and below uses [consolidate](https://github.com/tj/consolidate.js/) to compile `<template lang="xxx">`. v15 now applies preprocessing for them using webpack loaders instead.

Note that some template loaders such as `pug-loader` exports a compiled templating function instead of plain HTML. In order to pass the correct content to Vue's template compiler, you must use a loader that outputs plain HTML instead. For example, to support `<template lang="pug">`, you can use [pug-plain-loader](https://github.com/yyx990803/pug-plain-loader):

``` js
{
module: {
rules: [
{
test: /\.pug$/,
loader: 'pug-plain-loader'
}
]
}
}
```

If you also intend to use it to import .pug files as HTML strings in JavaScript, you will need to chain `raw-loader` after the preprocessing loader. Note however adding raw-loader would break the usage in Vue components, so you need to have two rules, one of them excluding Vue components:

``` js
{
module: {
rules: [
{
test: /\.pug$/,
oneOf: [
// this applies to <template lang="pug"> in Vue components
{
resourceQuery: /^\?vue/,
use: ['pug-plain-loader']
},
// this applies to pug imports inside JavaScript
{
use: ['raw-loader', 'pug-plain-loader']
}
]
}
]
}
}
```

### Style Injection

Client-side style injection now injects all styles upfront to ensure consistent behavior between development and extracted mode.
Expand Down Expand Up @@ -200,6 +244,7 @@ The following options have been deprecated and should be configured using normal
- `cssSourceMap`
- `buble`
- `extractCSS`
- `template`

The following options have been deprecated and should be configured using the new `compilerOptions` option:

Expand Down
7 changes: 7 additions & 0 deletions example/debugger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = function (...args) {
this.callback(null, ...args)
}

module.exports.pitch = function (request) {
// debug
}
7 changes: 3 additions & 4 deletions example/source.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<template>
<div>
<h1 :class="$style.red">{{ msg }}</h1>
</div>
<template lang="pug">
div(ok)
h1(:class="$style.red") hello
</template>

<script>
Expand Down
2 changes: 2 additions & 0 deletions example/test.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
div(ok)
h1(:class="$style.red") hello
32 changes: 25 additions & 7 deletions example/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,37 @@ module.exports = {
},
module: {
rules: [
// { loader: require.resolve('./debugger') },
{
test: /\.vue$/,
loader: 'vue-loader'
},
// example to apply loader to a custom block without lang="xxx"
// this rule applies to <foo> blocks
{
resourceQuery: /blockType=foo/,
loader: 'babel-loader'
},
// example configuring preprocessor for <template lang="pug">
{
test: /\.pug$/,
oneOf: [
// this applies to <template lang="pug"> in Vue components
{
resourceQuery: /^\?vue/,
use: ['pug-plain-loader']
},
// this applies to pug imports inside JavaScript
{
use: ['raw-loader', 'pug-plain-loader']
}
]
},
// example configuring CSS Modules
{
test: /\.css$/,
oneOf: [
// this applies to <style module>
{
resourceQuery: /module/,
use: [
Expand All @@ -39,6 +59,7 @@ module.exports = {
}
]
},
// this applies to <style> or <style scoped>
{
use: [
'vue-style-loader',
Expand All @@ -47,19 +68,16 @@ module.exports = {
}
]
},
// exmaple configration for <style lang="scss">
{
test: /\.scss$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]_[hash:base64:8]'
}
},
'css-loader',
{
loader: 'sass-loader',
// global data for all components
// this can be read from a scss file
options: {
data: '$color: red;'
}
Expand Down
3 changes: 0 additions & 3 deletions lib/loaders/templateLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ module.exports = function (source) {
filename: this.resourcePath,
compiler,
compilerOptions,
// handle possible lang="xxx"
preprocessLang: query.lang,
preprocessOptions: options.template,
// allow customizing behavior of vue-template-es2015-compiler
transpileOptions: options.transpileOptions,
transformAssetUrls: options.transformAssetUrls || true,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"normalize-newline": "^3.0.0",
"postcss-loader": "^2.1.2",
"pug": "^2.0.1",
"pug-plain-loader": "^1.0.0",
"raw-loader": "^0.5.1",
"sass-loader": "^6.0.7",
"stylus": "^0.54.5",
Expand Down
28 changes: 26 additions & 2 deletions test/core.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@ test('pre-processors', done => {
module: {
rules: [
{
test: /\.js/,
test: /\.js$/,
loader: 'babel-loader'
},
{
test: /\.stylus/,
test: /\.pug$/,
loader: 'pug-plain-loader'
},
{
test: /\.stylus$/,
use: [
'vue-style-loader',
'css-loader',
Expand Down Expand Up @@ -112,6 +116,26 @@ test('template import', done => {
})
})

test('template import with pre-processors', done => {
mockBundleAndRun({
entry: 'template-import-pre.vue',
module: {
rules: [
{
test: /\.pug$/,
loader: 'pug-plain-loader'
}
]
}
}, ({ window, module }) => {
const vnode = mockRender(module)
// '<div><h1>hello</h1></div>'
expect(vnode.children[0].tag).toBe('h1')
expect(vnode.children[0].children[0].text).toBe('hello')
done()
})
})

test('script import', done => {
mockBundleAndRun({
entry: 'script-import.vue'
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/template-import-pre.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<template lang="pug" src="./template-import.pug"></template>
3 changes: 3 additions & 0 deletions test/fixtures/template-import.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
<h1>hello</h1>
</div>
2 changes: 1 addition & 1 deletion test/fixtures/template-import.vue
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<template lang="pug" src="./template-import.pug"></template>
<template src="./template-import.html"></template>
9 changes: 9 additions & 0 deletions test/fixtures/template-pre.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Comp1 from './template-pre.vue'
import Comp2 from './template-import-pre.vue'
import html from './template-import.pug'

window.exports = {
Comp1,
Comp2,
html
}
4 changes: 4 additions & 0 deletions test/fixtures/template-pre.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<template lang="pug">
div
h1 hello
</template>
40 changes: 40 additions & 0 deletions test/template.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,43 @@ test('custom compiler directives', done => {
done()
})
})

test('separate loader configuration for template lang and js imports', done => {
mockBundleAndRun({
entry: './test/fixtures/template-pre.js',
module: {
rules: [
{
test: /\.pug$/,
oneOf: [
// this applies to <template lang="pug"> in Vue components
{
resourceQuery: /^\?vue/,
use: ['pug-plain-loader']
},
// this applies to pug imports inside JavaScript
{
use: ['raw-loader', 'pug-plain-loader']
}
]
}
]
}
}, ({ exports }) => {
function assertRender (vnode) {
expect(vnode.tag).toBe('div')
expect(vnode.children[0].tag).toBe('h1')
expect(vnode.children[0].children[0].text).toBe('hello')
}

// <template lang="pug">
const vnode1 = mockRender(exports.Comp1, {})
assertRender(vnode1)
// <template lang="pug" src="./foo.pug">
const vnode2 = mockRender(exports.Comp2, {})
assertRender(vnode2)
// import html from './foo.pug'
expect(exports.html).toBe('<div><h1>hello</h1></div>')
done()
})
})
6 changes: 6 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6646,6 +6646,12 @@ pug-parser@^5.0.0:
pug-error "^1.3.2"
token-stream "0.0.1"

pug-plain-loader@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/pug-plain-loader/-/pug-plain-loader-1.0.0.tgz#cef2a984c90251882109ec2d417a6b433aa6b42a"
dependencies:
loader-utils "^1.1.0"

pug-runtime@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-2.0.4.tgz#e178e1bda68ab2e8c0acfc9bced2c54fd88ceb58"
Expand Down

0 comments on commit c954f32

Please sign in to comment.