diff --git a/README.md b/README.md
index 59fa76f..5e3ecf7 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,8 @@ export default {
### Options
+#### `css`
+
```js
vue({
// Filename to write all styles to
@@ -95,6 +97,15 @@ vue({
})
```
+#### `compileTemplate`
+
+```js
+vue({
+ // Compile templates to render functions (Vue 2 only)
+ compileTemplate: true,
+})
+```
+
## Change log
Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.
diff --git a/package.json b/package.json
index 373b1c1..3e7d36c 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"html-minifier": "latest",
"parse5": "latest",
"rollup-pluginutils": "latest",
+ "vue-template-compiler": "^2.0.0-rc.4",
"vue-template-validator": "latest"
},
"devDependencies": {
diff --git a/src/index.js b/src/index.js
index b4d9502..3647e6d 100644
--- a/src/index.js
+++ b/src/index.js
@@ -7,6 +7,7 @@ export default function vue(options = {}) {
const filter = createFilter(options.include, options.exclude);
const styles = {};
let dest = options.css;
+ const compileTemplate = !!options.compileTemplate;
return {
name: 'vue',
@@ -19,7 +20,7 @@ export default function vue(options = {}) {
return null;
}
- const { js, css } = vueTransform(source, id);
+ const { js, css } = vueTransform(source, id, { compileTemplate });
// Map of every stylesheet
styles[id] = css || {};
@@ -27,7 +28,11 @@ export default function vue(options = {}) {
// Component javascript with inlined html template
return js;
},
- ongenerate(opts) {
+ ongenerate(opts, rendered) {
+ // Put with statements back
+ /* eslint-disable no-param-reassign */
+ rendered.code = rendered.code.replace(/if\s*\(""__VUE_WITH_STATEMENT__"\)/g,
+ 'with(this)');
if (options.css === false) {
return;
}
diff --git a/src/options.js b/src/options.js
index 2c39717..b05e800 100644
--- a/src/options.js
+++ b/src/options.js
@@ -12,4 +12,5 @@ export default {
removeEmptyAttributes: true,
removeOptionalTags: true,
},
+ VUE_WITH_STATEMENT: '__VUE_WITH_STATEMENT__',
};
diff --git a/src/vueTransform.js b/src/vueTransform.js
index 4d20df2..c0f68e7 100644
--- a/src/vueTransform.js
+++ b/src/vueTransform.js
@@ -1,5 +1,6 @@
import deIndent from 'de-indent';
import htmlMinifier from 'html-minifier';
+import { compile as compileTemplate } from 'vue-template-compiler';
import parse5 from 'parse5';
import validateTemplate from 'vue-template-validator';
import { relative } from 'path';
@@ -38,6 +39,39 @@ function padContent(content) {
.join('\n');
}
+/**
+ * Wrap code inside a with statement inside a function
+ * This is necessary for Vue 2 template compilation
+ *
+ * @param {string} code
+ * @returns {string}
+ */
+function wrapRenderFunction(code) {
+ // Replace with(this) by something that works on strict mode
+ // https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js
+ return `function(){${code.replace(/with\(this\)/g, 'if("__VUE_WITH_STATEMENT__")')}}`;
+}
+
+/**
+ * Only support for es5 modules
+ *
+ * @param script
+ * @param render
+ * @returns {string}
+ */
+function injectRender(script, render) {
+ const matches = /(export default[^{]*\{)/g.exec(script);
+ if (matches) {
+ return script.split(matches[1])
+ .join(`${matches[1]}` +
+ `render: ${wrapRenderFunction(render.render)},` +
+ 'staticRenderFns: [' +
+ `${render.staticRenderFns.map(wrapRenderFunction).join(',')}],`
+ );
+ }
+ throw new Error('[rollup-plugin-vue] could not find place to inject template in script.');
+}
+
/**
* Only support for es5 modules
*
@@ -78,19 +112,24 @@ function processTemplate(node, filePath, content) {
* @param {string} content
* @param {string} template
*/
-function processScript(node, filePath, content, template) {
+function processScript(node, filePath, content, { template, render }) {
const lang = checkLang(node) || 'js';
let script = parse5.serialize(node);
// pad the script to ensure correct line number for syntax errors
const location = content.indexOf(script);
const before = padContent(content.slice(0, location));
script = before + script;
- script = injectTemplate(script, template, lang);
+ if (template) {
+ script = injectTemplate(script, template, lang);
+ } else if (render) {
+ script = injectRender(script, render, lang);
+ }
script = deIndent(script);
+
return script;
}
-export default function vueTransform(code, filePath) {
+export default function vueTransform(code, filePath, transformOptions) {
// 1. Parse the file into an HTML tree
const fragment = parse5.parseFragment(code, { locationInfo: true });
@@ -108,10 +147,17 @@ export default function vueTransform(code, filePath) {
// 4. Process template
const template = processTemplate(nodes.template, filePath, code);
+ let js;
+ if (transformOptions.compileTemplate) {
+ const render = compileTemplate(template);
+ js = processScript(nodes.script, filePath, code, { render });
+ } else {
+ js = processScript(nodes.script, filePath, code, { template });
+ }
// 5. Process script & style
return {
- js: processScript(nodes.script, filePath, code, template),
+ js,
css: nodes.style && {
content: parse5.serialize(nodes.style),
lang: checkLang(nodes.style),
diff --git a/test/expects/compileTemplate.js b/test/expects/compileTemplate.js
new file mode 100755
index 0000000..95a5d7a
--- /dev/null
+++ b/test/expects/compileTemplate.js
@@ -0,0 +1,9 @@
+var compileTemplate = {render: function(){if("__VUE_WITH_STATEMENT__"){return _h('div',[_h('p',[_s(msg)])])}},staticRenderFns: [],
+ data() {
+ return {
+ msg: 'Compile Template'
+ }
+ }
+}
+
+export default compileTemplate;
\ No newline at end of file
diff --git a/test/fixtures/compileTemplate.vue b/test/fixtures/compileTemplate.vue
new file mode 100755
index 0000000..d5306ff
--- /dev/null
+++ b/test/fixtures/compileTemplate.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/test/test.js b/test/test.js
index 5c3f651..912edef 100644
--- a/test/test.js
+++ b/test/test.js
@@ -23,7 +23,8 @@ function test(name) {
plugins: [vuePlugin({
css (css) {
actualCss = css
- }
+ },
+ compileTemplate: name === 'compileTemplate'
})]
}).then(function (bundle) {
var result = bundle.generate()