Skip to content
This repository was archived by the owner on Jan 18, 2022. It is now read-only.

Commit ce3af3d

Browse files
posvaznck
authored andcommitted
Compile Vue 2 templates
Fix #19 Compile Vue 2 templates (#15) * wip compile templates * Fix missing characters * Replace with statements before returning them * Add option compileTemplate * Fix coding style * Divide into multiple lines * Add missing trailing , * Test compileTemplate option * Added option to readme
1 parent 7b45ae4 commit ce3af3d

File tree

8 files changed

+96
-7
lines changed

8 files changed

+96
-7
lines changed

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ export default {
7575

7676
### Options
7777

78+
#### `css`
79+
7880
```js
7981
vue({
8082
// Filename to write all styles to
@@ -95,6 +97,15 @@ vue({
9597
})
9698
```
9799

100+
#### `compileTemplate`
101+
102+
```js
103+
vue({
104+
// Compile templates to render functions (Vue 2 only)
105+
compileTemplate: true,
106+
})
107+
```
108+
98109
## Change log
99110

100111
Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"html-minifier": "latest",
3131
"parse5": "latest",
3232
"rollup-pluginutils": "latest",
33+
"vue-template-compiler": "^2.0.0-rc.4",
3334
"vue-template-validator": "latest"
3435
},
3536
"devDependencies": {

src/index.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export default function vue(options = {}) {
77
const filter = createFilter(options.include, options.exclude);
88
const styles = {};
99
let dest = options.css;
10+
const compileTemplate = !!options.compileTemplate;
1011

1112
return {
1213
name: 'vue',
@@ -19,15 +20,19 @@ export default function vue(options = {}) {
1920
return null;
2021
}
2122

22-
const { js, css } = vueTransform(source, id);
23+
const { js, css } = vueTransform(source, id, { compileTemplate });
2324

2425
// Map of every stylesheet
2526
styles[id] = css || {};
2627

2728
// Component javascript with inlined html template
2829
return js;
2930
},
30-
ongenerate(opts) {
31+
ongenerate(opts, rendered) {
32+
// Put with statements back
33+
/* eslint-disable no-param-reassign */
34+
rendered.code = rendered.code.replace(/if\s*\(""__VUE_WITH_STATEMENT__"\)/g,
35+
'with(this)');
3136
if (options.css === false) {
3237
return;
3338
}

src/options.js

+1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ export default {
1212
removeEmptyAttributes: true,
1313
removeOptionalTags: true,
1414
},
15+
VUE_WITH_STATEMENT: '__VUE_WITH_STATEMENT__',
1516
};

src/vueTransform.js

+50-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import deIndent from 'de-indent';
22
import htmlMinifier from 'html-minifier';
3+
import { compile as compileTemplate } from 'vue-template-compiler';
34
import parse5 from 'parse5';
45
import validateTemplate from 'vue-template-validator';
56
import { relative } from 'path';
@@ -38,6 +39,39 @@ function padContent(content) {
3839
.join('\n');
3940
}
4041

42+
/**
43+
* Wrap code inside a with statement inside a function
44+
* This is necessary for Vue 2 template compilation
45+
*
46+
* @param {string} code
47+
* @returns {string}
48+
*/
49+
function wrapRenderFunction(code) {
50+
// Replace with(this) by something that works on strict mode
51+
// https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js
52+
return `function(){${code.replace(/with\(this\)/g, 'if("__VUE_WITH_STATEMENT__")')}}`;
53+
}
54+
55+
/**
56+
* Only support for es5 modules
57+
*
58+
* @param script
59+
* @param render
60+
* @returns {string}
61+
*/
62+
function injectRender(script, render) {
63+
const matches = /(export default[^{]*\{)/g.exec(script);
64+
if (matches) {
65+
return script.split(matches[1])
66+
.join(`${matches[1]}` +
67+
`render: ${wrapRenderFunction(render.render)},` +
68+
'staticRenderFns: [' +
69+
`${render.staticRenderFns.map(wrapRenderFunction).join(',')}],`
70+
);
71+
}
72+
throw new Error('[rollup-plugin-vue] could not find place to inject template in script.');
73+
}
74+
4175
/**
4276
* Only support for es5 modules
4377
*
@@ -78,19 +112,24 @@ function processTemplate(node, filePath, content) {
78112
* @param {string} content
79113
* @param {string} template
80114
*/
81-
function processScript(node, filePath, content, template) {
115+
function processScript(node, filePath, content, { template, render }) {
82116
const lang = checkLang(node) || 'js';
83117
let script = parse5.serialize(node);
84118
// pad the script to ensure correct line number for syntax errors
85119
const location = content.indexOf(script);
86120
const before = padContent(content.slice(0, location));
87121
script = before + script;
88-
script = injectTemplate(script, template, lang);
122+
if (template) {
123+
script = injectTemplate(script, template, lang);
124+
} else if (render) {
125+
script = injectRender(script, render, lang);
126+
}
89127
script = deIndent(script);
128+
90129
return script;
91130
}
92131

93-
export default function vueTransform(code, filePath) {
132+
export default function vueTransform(code, filePath, transformOptions) {
94133
// 1. Parse the file into an HTML tree
95134
const fragment = parse5.parseFragment(code, { locationInfo: true });
96135

@@ -108,10 +147,17 @@ export default function vueTransform(code, filePath) {
108147

109148
// 4. Process template
110149
const template = processTemplate(nodes.template, filePath, code);
150+
let js;
151+
if (transformOptions.compileTemplate) {
152+
const render = compileTemplate(template);
153+
js = processScript(nodes.script, filePath, code, { render });
154+
} else {
155+
js = processScript(nodes.script, filePath, code, { template });
156+
}
111157

112158
// 5. Process script & style
113159
return {
114-
js: processScript(nodes.script, filePath, code, template),
160+
js,
115161
css: nodes.style && {
116162
content: parse5.serialize(nodes.style),
117163
lang: checkLang(nodes.style),

test/expects/compileTemplate.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
var compileTemplate = {render: function(){if("__VUE_WITH_STATEMENT__"){return _h('div',[_h('p',[_s(msg)])])}},staticRenderFns: [],
2+
data() {
3+
return {
4+
msg: 'Compile Template'
5+
}
6+
}
7+
}
8+
9+
export default compileTemplate;

test/fixtures/compileTemplate.vue

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<div>
3+
<p>{{msg}}</p>
4+
</div>
5+
</template>
6+
7+
<script>
8+
export default {
9+
data() {
10+
return {
11+
msg: 'Compile Template'
12+
}
13+
}
14+
}
15+
</script>

test/test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ function test(name) {
2323
plugins: [vuePlugin({
2424
css (css) {
2525
actualCss = css
26-
}
26+
},
27+
compileTemplate: name === 'compileTemplate'
2728
})]
2829
}).then(function (bundle) {
2930
var result = bundle.generate()

0 commit comments

Comments
 (0)