rollup-plugin-vue
Advanced tools
Comparing version 2.2.10 to 2.2.11
@@ -18,19 +18,16 @@ 'use strict'; | ||
/** | ||
* Check the lang attribute of a parse5 node. | ||
* | ||
* @param {Node|*} node | ||
* @return {String|undefined} | ||
*/ | ||
function checkLang(node) { | ||
if (node.attrs) { | ||
for (var i = 0, list = node.attrs; i < list.length; i += 1) { | ||
var attr = list[i]; | ||
function getNodeAttrs(node) { | ||
if (node.attrs) { | ||
var attributes = {}; | ||
if (attr.name === 'lang') { | ||
return attr.value; | ||
} | ||
} | ||
for (var i = 0, list = node.attrs; i < list.length; i += 1) { | ||
var attr = list[i]; | ||
attributes[attr.name] = attr.value; | ||
} | ||
return undefined; | ||
return attributes; | ||
} | ||
return {}; | ||
} | ||
@@ -40,5 +37,2 @@ | ||
* Pad content with empty lines to get correct line number in errors. | ||
* | ||
* @param content | ||
* @returns {string} | ||
*/ | ||
@@ -55,5 +49,2 @@ function padContent(content) { | ||
* This is necessary for Vue 2 template compilation | ||
* | ||
* @param {string} code | ||
* @returns {string} | ||
*/ | ||
@@ -64,38 +55,19 @@ function wrapRenderFunction(code) { | ||
/** | ||
* Only support for es5 modules | ||
* | ||
* @param script | ||
* @param render | ||
* @param lang | ||
* @returns {string} | ||
*/ | ||
function injectRender(script, render, lang) { | ||
function injectRender(script, render, lang, options) { | ||
if (['js', 'babel'].indexOf(lang.toLowerCase()) > -1) { | ||
var matches = /(export default[^{]*\{)/g.exec(script); | ||
if (matches) { | ||
var scriptWithRender = script.split(matches[1]) | ||
// buble doesn't support export default, not even with the | ||
// module: false trasforms: | ||
// https://buble.surge.sh/guide/#using-es-modules | ||
.join('module.exports={' + | ||
"render: " + (wrapRenderFunction(render.render)) + "," + | ||
'staticRenderFns: [' + | ||
(render.staticRenderFns.map(wrapRenderFunction).join(',')) + "]," | ||
); | ||
return transpileVueTemplate(scriptWithRender, { | ||
// Remove all trasforms added by vue since it's up to the user | ||
// to use whatever he wants | ||
// https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js#L6 | ||
transforms: { | ||
templateString: false, | ||
conciseMethodProperty: false, | ||
stripWith: true, // remove the with statement | ||
computedProperty: false, | ||
}, | ||
// put back the export default { | ||
}).replace('module.exports={', 'export default {'); | ||
var renderScript = transpileVueTemplate('module.exports={' + | ||
"render: " + (wrapRenderFunction(render.render)) + "," + | ||
'staticRenderFns: [' + | ||
(render.staticRenderFns.map(wrapRenderFunction).join(',')) + "],}", options.vue); | ||
var result = script.split(matches[1]) | ||
.join(renderScript.replace('module.exports={', 'export default {').replace(/\}$/, '')); | ||
return result; | ||
} | ||
debug$1(("No injection location found in: \n" + script + "\n")); | ||
} else if (options.inject) { | ||
return options.inject(script, render, lang, options); | ||
} | ||
@@ -111,3 +83,5 @@ throw new Error('[rollup-plugin-vue] could not find place to inject template in script.'); | ||
*/ | ||
function injectTemplate(script, template, lang) { | ||
function injectTemplate(script, template, lang, options) { | ||
if (template === undefined) { return script; } | ||
if (['js', 'babel'].indexOf(lang.toLowerCase()) > -1) { | ||
@@ -121,3 +95,6 @@ var matches = /(export default[^{]*\{)/g.exec(script); | ||
debug$1(("No injection location found in: \n" + script + "\n")); | ||
} else if (options.inject) { | ||
return options.inject(script, template, lang, options); | ||
} | ||
throw new Error('[rollup-plugin-vue] could not find place to inject template in script.'); | ||
@@ -128,12 +105,12 @@ } | ||
* Compile template: DeIndent and minify html. | ||
* @param {Node} node | ||
* @param {string} filePath | ||
* @param {string} content | ||
* @param {*} options | ||
*/ | ||
function processTemplate(node, filePath, content, options) { | ||
node = node.content; | ||
var warnings = validateTemplate(node, content); | ||
function processTemplate(source, id, content, options) { | ||
if (source === undefined) { return undefined; } | ||
var node = source.node; | ||
var code = source.code; | ||
var warnings = validateTemplate(code, content); | ||
if (warnings) { | ||
var relativePath = path.relative(process.cwd(), filePath); | ||
var relativePath = path.relative(process.cwd(), id); | ||
warnings.forEach(function (msg) { | ||
@@ -145,4 +122,4 @@ console.warn(("\n Warning in " + relativePath + ":\n " + msg)); | ||
/* eslint-disable no-underscore-dangle */ | ||
var start = node.childNodes[0].__location.startOffset; | ||
var end = node.childNodes[node.childNodes.length - 1].__location.endOffset; | ||
var start = node.content.childNodes[0].__location.startOffset; | ||
var end = node.content.childNodes[node.content.childNodes.length - 1].__location.endOffset; | ||
var template = deIndent(content.slice(start, end)); | ||
@@ -154,78 +131,64 @@ /* eslint-enable no-underscore-dangle */ | ||
/** | ||
* @param {Node|ASTNode} node | ||
* @param {string} filePath | ||
* @param {string} content | ||
* @param templateOrRender | ||
*/ | ||
function processScript(node, filePath, content, templateOrRender) { | ||
var lang = checkLang(node) || 'js'; | ||
var template = templateOrRender.template; | ||
var render = templateOrRender.render; | ||
var script = parse5.serialize(node); | ||
function processScript(source, id, content, options, nodes) { | ||
var template = processTemplate(nodes.template[0], id, content, options, nodes); | ||
// pad the script to ensure correct line number for syntax errors | ||
var location = content.indexOf(script); | ||
var before = padContent(content.slice(0, location)); | ||
script = before + script; | ||
var lang = source.attrs.lang || 'js'; | ||
var map = new MagicString(script); | ||
var script = deIndent(padContent(content.slice(0, content.indexOf(source.code))) + source.code); | ||
var map = (new MagicString(script)).generateMap({ hires: true }); | ||
if (template) { | ||
script = injectTemplate(script, template, lang); | ||
} else if (render) { | ||
script = injectRender(script, render, lang); | ||
if (options.compileTemplate) { | ||
var render = require('vue-template-compiler').compile(template); | ||
return { map: map, code: injectRender(script, render, lang, options) }; | ||
} else { | ||
debug$1('Nothing to inject!'); | ||
return { map: map, code: injectTemplate(script, template, lang, options) }; | ||
} | ||
} | ||
script = deIndent(script); | ||
return { | ||
code: script, | ||
map: map, | ||
}; | ||
function processStyle(styles, id) { | ||
return styles.map(function (style) { return ({ | ||
id: id, | ||
code: deIndent(style.code).trim(), | ||
lang: style.attrs.lang || 'css', | ||
}); }); | ||
} | ||
function vueTransform(code, filePath, options) { | ||
// 1. Parse the file into an HTML tree | ||
var fragment = parse5.parseFragment(code, { locationInfo: true }); | ||
function parseTemplate(code) { | ||
var fragment = parse5.parseFragment(code, { locationInfo: true }); | ||
// 2. Walk through the top level nodes and check for their types | ||
var nodes = {}; | ||
for (var i = fragment.childNodes.length - 1; i >= 0; i -= 1) { | ||
nodes[fragment.childNodes[i].nodeName] = fragment.childNodes[i]; | ||
} | ||
var nodes = { | ||
template: [], | ||
script: [], | ||
style: [], | ||
}; | ||
// 3. Don't touch files that don't look like Vue components | ||
if (!nodes.script) { | ||
throw new Error('There must be at least one script tag or one' + | ||
' template tag per *.vue file.'); | ||
} | ||
for (var i = fragment.childNodes.length - 1; i >= 0; i -= 1) { | ||
var name = fragment.childNodes[i].nodeName; | ||
if (! (name in nodes)) { | ||
nodes[name] = []; | ||
} | ||
nodes[name].push({ | ||
node: fragment.childNodes[i], | ||
code: parse5.serialize(fragment.childNodes[i]), | ||
attrs: getNodeAttrs(fragment.childNodes[i]), | ||
}); | ||
} | ||
// 4. Process template | ||
var template = nodes.template | ||
? processTemplate(nodes.template, filePath, code, options) | ||
: undefined; | ||
var js; | ||
if (options.compileTemplate) { | ||
/* eslint-disable */ | ||
var render = template ? require('vue-template-compiler').compile(template) : undefined; | ||
/* eslint-enable */ | ||
js = processScript(nodes.script, filePath, code, { render: render }); | ||
} else { | ||
js = processScript(nodes.script, filePath, code, { template: template }); | ||
} | ||
if (nodes.script.length === 0) { | ||
throw new Error('There must be at least one script tag or one' + | ||
' template tag per *.vue file.'); | ||
} | ||
// 5. Process script & style | ||
return { | ||
js: js.code, | ||
map: js.map, | ||
css: nodes.style && { | ||
content: parse5.serialize(nodes.style), | ||
lang: checkLang(nodes.style), | ||
}, | ||
}; | ||
return nodes; | ||
} | ||
function vueTransform(code, id, options) { | ||
var nodes = parseTemplate(code); | ||
var js = processScript(nodes.script[0], id, code, options, nodes); | ||
var css = processStyle(nodes.style, id, code, options, nodes); | ||
return { css: css, code: js.code, map: js.map }; | ||
} | ||
var DEFAULT_OPTIONS = { | ||
@@ -237,4 +200,75 @@ htmlMinifier: { | ||
}, | ||
vue: { | ||
// Remove all trasforms added by vue since it's up to the user | ||
// to use whatever he wants | ||
// https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js#L6 | ||
transforms: { | ||
stripWith: true, // remove the with statement | ||
arrow: false, | ||
classes: false, | ||
collections: false, | ||
computedProperty: false, | ||
conciseMethodProperty: false, | ||
constLoop: false, | ||
dangerousForOf: false, | ||
dangerousTaggedTemplateString: false, | ||
defaultParameter: false, | ||
destructuring: false, | ||
forOf: false, | ||
generator: false, | ||
letConst: false, | ||
modules: false, | ||
numericLiteral: false, | ||
parameterDestructuring: false, | ||
reservedProperties: false, | ||
spreadRest: false, | ||
stickyRegExp: false, | ||
templateString: false, | ||
unicodeRegExp: false, | ||
}, | ||
} | ||
}; | ||
var compileStyle = function (files, options) { | ||
if (options.css === false) { | ||
return; | ||
} | ||
// Combine all stylesheets. | ||
var css = ''; | ||
var allStyles = []; | ||
Object.keys(files).forEach(function (file) { | ||
files[file].forEach(function (style) { | ||
css += style.code + '\n'; | ||
allStyles.push(style); | ||
}); | ||
}); | ||
// Emit styles through callback | ||
if (typeof options.css === 'function') { | ||
options.css(css, allStyles); | ||
return; | ||
} | ||
// Don't generate empty style file. | ||
if (!css.trim().length) { | ||
return; | ||
} | ||
var dest = options.css; | ||
if (typeof dest !== 'string') { | ||
return; | ||
} | ||
// Emit styles to file | ||
writeFile(dest, css, function (err) { | ||
if (err) { throw err; } | ||
emitted(dest, css.length); | ||
}); | ||
}; | ||
function mergeOptions(options, defaults) { | ||
@@ -279,4 +313,3 @@ Object.keys(defaults).forEach(function (key) { | ||
} | ||
} catch (e) { | ||
} | ||
} catch (e) {} | ||
/* eslint-enable */ | ||
@@ -287,60 +320,5 @@ | ||
var styles = {}; | ||
var rollupOptions; | ||
var generated = false; | ||
var generateStyleBundle = function () { | ||
if (options.css === false) { | ||
return; | ||
} | ||
if (generated) { | ||
debug$1('Style already generated!'); | ||
return; | ||
} | ||
generated = true; | ||
// Combine all stylesheets. | ||
var css = ''; | ||
Object.keys(styles).forEach(function (key) { | ||
css += styles[key].content || ''; | ||
}); | ||
// Emit styles through callback | ||
if (typeof options.css === 'function') { | ||
options.css(css, styles); | ||
return; | ||
} | ||
// Don't generate empty style file. | ||
if (!css.trim().length) { | ||
return; | ||
} | ||
var dest = options.css; | ||
if (typeof dest !== 'string') { | ||
// Guess destination filename | ||
dest = rollupOptions.dest || 'bundle.js'; | ||
if (dest.endsWith('.js')) { | ||
dest = dest.slice(0, -3); | ||
} | ||
dest = dest + ".css"; | ||
} | ||
// Emit styles to file | ||
fs.writeFile(dest, css, function (err) { | ||
if (err) { | ||
throw err; | ||
} | ||
emitted(dest, css.length); | ||
}); | ||
}; | ||
return { | ||
name: 'vue', | ||
options: function options$1(o) { | ||
if (rollupOptions === undefined) { | ||
rollupOptions = o; | ||
debug$1('Set options.'); | ||
} | ||
}, | ||
transform: function transform(source, id) { | ||
@@ -353,58 +331,21 @@ if (!filter(id) || !id.endsWith('.vue')) { | ||
debug$1(("Transform: " + id)); | ||
var ref = vueTransform(source, id, options); | ||
var js = ref.js; | ||
var code = ref.code; | ||
var css = ref.css; | ||
var map = ref.map; | ||
// Map of every stylesheet | ||
styles[id] = css || {}; | ||
styles[id] = css; | ||
// Component javascript with inlined html template | ||
var result = { | ||
code: js, | ||
map: map.generateMap({ hires: true }), | ||
}; | ||
debug$1(("Transformed: " + id)); | ||
return result; | ||
return { code: code, map: map }; | ||
}, | ||
transformBundle: function transformBundle(source) { | ||
generateStyleBundle(); | ||
var map = new MagicString(source); | ||
var result = { | ||
code: source, | ||
map: map.generateMap({ hires: true }), | ||
}; | ||
debug$1('with(this) fixed!'); | ||
return result; | ||
}, | ||
ongenerate: function ongenerate(opts, rendered) { | ||
debug$1('on generate!'); | ||
generateStyleBundle(); | ||
rendered.code = rendered.code.replace( | ||
/if[\s]*\(window\.__VUE_WITH_STATEMENT__\)/g, 'with(this)'); | ||
debug$1('with(this) fixed!'); | ||
}, | ||
ongenerate: function ongenerate() { | ||
compileStyle(styles, options); | ||
} | ||
}; | ||
} | ||
function emitted(text, bytes) { | ||
console.log(green(text), getSize(bytes)); | ||
} | ||
function green(text) { | ||
return ("\u001b[1m\u001b[32m" + text + "\u001b[39m\u001b[22m"); | ||
} | ||
function getSize(bytes) { | ||
if (bytes < 10000) { | ||
return ((bytes.toFixed(0)) + " B"); | ||
} | ||
return bytes < 1024000 | ||
? (((bytes / 1024).toPrecision(3)) + " kB'") | ||
: (((bytes / 1024 / 1024).toPrecision(4)) + " MB"); | ||
} | ||
module.exports = vue; |
import { createFilter } from 'rollup-pluginutils'; | ||
import { writeFile } from 'fs'; | ||
import 'fs'; | ||
import MagicString from 'magic-string'; | ||
@@ -14,19 +14,16 @@ import deIndent from 'de-indent'; | ||
/** | ||
* Check the lang attribute of a parse5 node. | ||
* | ||
* @param {Node|*} node | ||
* @return {String|undefined} | ||
*/ | ||
function checkLang(node) { | ||
if (node.attrs) { | ||
for (var i = 0, list = node.attrs; i < list.length; i += 1) { | ||
var attr = list[i]; | ||
function getNodeAttrs(node) { | ||
if (node.attrs) { | ||
var attributes = {}; | ||
if (attr.name === 'lang') { | ||
return attr.value; | ||
} | ||
} | ||
for (var i = 0, list = node.attrs; i < list.length; i += 1) { | ||
var attr = list[i]; | ||
attributes[attr.name] = attr.value; | ||
} | ||
return undefined; | ||
return attributes; | ||
} | ||
return {}; | ||
} | ||
@@ -36,5 +33,2 @@ | ||
* Pad content with empty lines to get correct line number in errors. | ||
* | ||
* @param content | ||
* @returns {string} | ||
*/ | ||
@@ -51,5 +45,2 @@ function padContent(content) { | ||
* This is necessary for Vue 2 template compilation | ||
* | ||
* @param {string} code | ||
* @returns {string} | ||
*/ | ||
@@ -60,38 +51,19 @@ function wrapRenderFunction(code) { | ||
/** | ||
* Only support for es5 modules | ||
* | ||
* @param script | ||
* @param render | ||
* @param lang | ||
* @returns {string} | ||
*/ | ||
function injectRender(script, render, lang) { | ||
function injectRender(script, render, lang, options) { | ||
if (['js', 'babel'].indexOf(lang.toLowerCase()) > -1) { | ||
var matches = /(export default[^{]*\{)/g.exec(script); | ||
if (matches) { | ||
var scriptWithRender = script.split(matches[1]) | ||
// buble doesn't support export default, not even with the | ||
// module: false trasforms: | ||
// https://buble.surge.sh/guide/#using-es-modules | ||
.join('module.exports={' + | ||
"render: " + (wrapRenderFunction(render.render)) + "," + | ||
'staticRenderFns: [' + | ||
(render.staticRenderFns.map(wrapRenderFunction).join(',')) + "]," | ||
); | ||
return transpileVueTemplate(scriptWithRender, { | ||
// Remove all trasforms added by vue since it's up to the user | ||
// to use whatever he wants | ||
// https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js#L6 | ||
transforms: { | ||
templateString: false, | ||
conciseMethodProperty: false, | ||
stripWith: true, // remove the with statement | ||
computedProperty: false, | ||
}, | ||
// put back the export default { | ||
}).replace('module.exports={', 'export default {'); | ||
var renderScript = transpileVueTemplate('module.exports={' + | ||
"render: " + (wrapRenderFunction(render.render)) + "," + | ||
'staticRenderFns: [' + | ||
(render.staticRenderFns.map(wrapRenderFunction).join(',')) + "],}", options.vue); | ||
var result = script.split(matches[1]) | ||
.join(renderScript.replace('module.exports={', 'export default {').replace(/\}$/, '')); | ||
return result; | ||
} | ||
debug$1(("No injection location found in: \n" + script + "\n")); | ||
} else if (options.inject) { | ||
return options.inject(script, render, lang, options); | ||
} | ||
@@ -107,3 +79,5 @@ throw new Error('[rollup-plugin-vue] could not find place to inject template in script.'); | ||
*/ | ||
function injectTemplate(script, template, lang) { | ||
function injectTemplate(script, template, lang, options) { | ||
if (template === undefined) { return script; } | ||
if (['js', 'babel'].indexOf(lang.toLowerCase()) > -1) { | ||
@@ -117,3 +91,6 @@ var matches = /(export default[^{]*\{)/g.exec(script); | ||
debug$1(("No injection location found in: \n" + script + "\n")); | ||
} else if (options.inject) { | ||
return options.inject(script, template, lang, options); | ||
} | ||
throw new Error('[rollup-plugin-vue] could not find place to inject template in script.'); | ||
@@ -124,12 +101,12 @@ } | ||
* Compile template: DeIndent and minify html. | ||
* @param {Node} node | ||
* @param {string} filePath | ||
* @param {string} content | ||
* @param {*} options | ||
*/ | ||
function processTemplate(node, filePath, content, options) { | ||
node = node.content; | ||
var warnings = validateTemplate(node, content); | ||
function processTemplate(source, id, content, options) { | ||
if (source === undefined) { return undefined; } | ||
var node = source.node; | ||
var code = source.code; | ||
var warnings = validateTemplate(code, content); | ||
if (warnings) { | ||
var relativePath = relative(process.cwd(), filePath); | ||
var relativePath = relative(process.cwd(), id); | ||
warnings.forEach(function (msg) { | ||
@@ -141,4 +118,4 @@ console.warn(("\n Warning in " + relativePath + ":\n " + msg)); | ||
/* eslint-disable no-underscore-dangle */ | ||
var start = node.childNodes[0].__location.startOffset; | ||
var end = node.childNodes[node.childNodes.length - 1].__location.endOffset; | ||
var start = node.content.childNodes[0].__location.startOffset; | ||
var end = node.content.childNodes[node.content.childNodes.length - 1].__location.endOffset; | ||
var template = deIndent(content.slice(start, end)); | ||
@@ -150,78 +127,64 @@ /* eslint-enable no-underscore-dangle */ | ||
/** | ||
* @param {Node|ASTNode} node | ||
* @param {string} filePath | ||
* @param {string} content | ||
* @param templateOrRender | ||
*/ | ||
function processScript(node, filePath, content, templateOrRender) { | ||
var lang = checkLang(node) || 'js'; | ||
var template = templateOrRender.template; | ||
var render = templateOrRender.render; | ||
var script = parse5.serialize(node); | ||
function processScript(source, id, content, options, nodes) { | ||
var template = processTemplate(nodes.template[0], id, content, options, nodes); | ||
// pad the script to ensure correct line number for syntax errors | ||
var location = content.indexOf(script); | ||
var before = padContent(content.slice(0, location)); | ||
script = before + script; | ||
var lang = source.attrs.lang || 'js'; | ||
var map = new MagicString(script); | ||
var script = deIndent(padContent(content.slice(0, content.indexOf(source.code))) + source.code); | ||
var map = (new MagicString(script)).generateMap({ hires: true }); | ||
if (template) { | ||
script = injectTemplate(script, template, lang); | ||
} else if (render) { | ||
script = injectRender(script, render, lang); | ||
if (options.compileTemplate) { | ||
var render = require('vue-template-compiler').compile(template); | ||
return { map: map, code: injectRender(script, render, lang, options) }; | ||
} else { | ||
debug$1('Nothing to inject!'); | ||
return { map: map, code: injectTemplate(script, template, lang, options) }; | ||
} | ||
} | ||
script = deIndent(script); | ||
return { | ||
code: script, | ||
map: map, | ||
}; | ||
function processStyle(styles, id) { | ||
return styles.map(function (style) { return ({ | ||
id: id, | ||
code: deIndent(style.code).trim(), | ||
lang: style.attrs.lang || 'css', | ||
}); }); | ||
} | ||
function vueTransform(code, filePath, options) { | ||
// 1. Parse the file into an HTML tree | ||
var fragment = parse5.parseFragment(code, { locationInfo: true }); | ||
function parseTemplate(code) { | ||
var fragment = parse5.parseFragment(code, { locationInfo: true }); | ||
// 2. Walk through the top level nodes and check for their types | ||
var nodes = {}; | ||
for (var i = fragment.childNodes.length - 1; i >= 0; i -= 1) { | ||
nodes[fragment.childNodes[i].nodeName] = fragment.childNodes[i]; | ||
} | ||
var nodes = { | ||
template: [], | ||
script: [], | ||
style: [], | ||
}; | ||
// 3. Don't touch files that don't look like Vue components | ||
if (!nodes.script) { | ||
throw new Error('There must be at least one script tag or one' + | ||
' template tag per *.vue file.'); | ||
} | ||
for (var i = fragment.childNodes.length - 1; i >= 0; i -= 1) { | ||
var name = fragment.childNodes[i].nodeName; | ||
if (! (name in nodes)) { | ||
nodes[name] = []; | ||
} | ||
nodes[name].push({ | ||
node: fragment.childNodes[i], | ||
code: parse5.serialize(fragment.childNodes[i]), | ||
attrs: getNodeAttrs(fragment.childNodes[i]), | ||
}); | ||
} | ||
// 4. Process template | ||
var template = nodes.template | ||
? processTemplate(nodes.template, filePath, code, options) | ||
: undefined; | ||
var js; | ||
if (options.compileTemplate) { | ||
/* eslint-disable */ | ||
var render = template ? require('vue-template-compiler').compile(template) : undefined; | ||
/* eslint-enable */ | ||
js = processScript(nodes.script, filePath, code, { render: render }); | ||
} else { | ||
js = processScript(nodes.script, filePath, code, { template: template }); | ||
} | ||
if (nodes.script.length === 0) { | ||
throw new Error('There must be at least one script tag or one' + | ||
' template tag per *.vue file.'); | ||
} | ||
// 5. Process script & style | ||
return { | ||
js: js.code, | ||
map: js.map, | ||
css: nodes.style && { | ||
content: parse5.serialize(nodes.style), | ||
lang: checkLang(nodes.style), | ||
}, | ||
}; | ||
return nodes; | ||
} | ||
function vueTransform(code, id, options) { | ||
var nodes = parseTemplate(code); | ||
var js = processScript(nodes.script[0], id, code, options, nodes); | ||
var css = processStyle(nodes.style, id, code, options, nodes); | ||
return { css: css, code: js.code, map: js.map }; | ||
} | ||
var DEFAULT_OPTIONS = { | ||
@@ -233,4 +196,75 @@ htmlMinifier: { | ||
}, | ||
vue: { | ||
// Remove all trasforms added by vue since it's up to the user | ||
// to use whatever he wants | ||
// https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js#L6 | ||
transforms: { | ||
stripWith: true, // remove the with statement | ||
arrow: false, | ||
classes: false, | ||
collections: false, | ||
computedProperty: false, | ||
conciseMethodProperty: false, | ||
constLoop: false, | ||
dangerousForOf: false, | ||
dangerousTaggedTemplateString: false, | ||
defaultParameter: false, | ||
destructuring: false, | ||
forOf: false, | ||
generator: false, | ||
letConst: false, | ||
modules: false, | ||
numericLiteral: false, | ||
parameterDestructuring: false, | ||
reservedProperties: false, | ||
spreadRest: false, | ||
stickyRegExp: false, | ||
templateString: false, | ||
unicodeRegExp: false, | ||
}, | ||
} | ||
}; | ||
var compileStyle = function (files, options) { | ||
if (options.css === false) { | ||
return; | ||
} | ||
// Combine all stylesheets. | ||
var css = ''; | ||
var allStyles = []; | ||
Object.keys(files).forEach(function (file) { | ||
files[file].forEach(function (style) { | ||
css += style.code + '\n'; | ||
allStyles.push(style); | ||
}); | ||
}); | ||
// Emit styles through callback | ||
if (typeof options.css === 'function') { | ||
options.css(css, allStyles); | ||
return; | ||
} | ||
// Don't generate empty style file. | ||
if (!css.trim().length) { | ||
return; | ||
} | ||
var dest = options.css; | ||
if (typeof dest !== 'string') { | ||
return; | ||
} | ||
// Emit styles to file | ||
writeFile(dest, css, function (err) { | ||
if (err) { throw err; } | ||
emitted(dest, css.length); | ||
}); | ||
}; | ||
function mergeOptions(options, defaults) { | ||
@@ -275,4 +309,3 @@ Object.keys(defaults).forEach(function (key) { | ||
} | ||
} catch (e) { | ||
} | ||
} catch (e) {} | ||
/* eslint-enable */ | ||
@@ -283,60 +316,5 @@ | ||
var styles = {}; | ||
var rollupOptions; | ||
var generated = false; | ||
var generateStyleBundle = function () { | ||
if (options.css === false) { | ||
return; | ||
} | ||
if (generated) { | ||
debug$1('Style already generated!'); | ||
return; | ||
} | ||
generated = true; | ||
// Combine all stylesheets. | ||
var css = ''; | ||
Object.keys(styles).forEach(function (key) { | ||
css += styles[key].content || ''; | ||
}); | ||
// Emit styles through callback | ||
if (typeof options.css === 'function') { | ||
options.css(css, styles); | ||
return; | ||
} | ||
// Don't generate empty style file. | ||
if (!css.trim().length) { | ||
return; | ||
} | ||
var dest = options.css; | ||
if (typeof dest !== 'string') { | ||
// Guess destination filename | ||
dest = rollupOptions.dest || 'bundle.js'; | ||
if (dest.endsWith('.js')) { | ||
dest = dest.slice(0, -3); | ||
} | ||
dest = dest + ".css"; | ||
} | ||
// Emit styles to file | ||
writeFile(dest, css, function (err) { | ||
if (err) { | ||
throw err; | ||
} | ||
emitted(dest, css.length); | ||
}); | ||
}; | ||
return { | ||
name: 'vue', | ||
options: function options$1(o) { | ||
if (rollupOptions === undefined) { | ||
rollupOptions = o; | ||
debug$1('Set options.'); | ||
} | ||
}, | ||
transform: function transform(source, id) { | ||
@@ -349,58 +327,21 @@ if (!filter(id) || !id.endsWith('.vue')) { | ||
debug$1(("Transform: " + id)); | ||
var ref = vueTransform(source, id, options); | ||
var js = ref.js; | ||
var code = ref.code; | ||
var css = ref.css; | ||
var map = ref.map; | ||
// Map of every stylesheet | ||
styles[id] = css || {}; | ||
styles[id] = css; | ||
// Component javascript with inlined html template | ||
var result = { | ||
code: js, | ||
map: map.generateMap({ hires: true }), | ||
}; | ||
debug$1(("Transformed: " + id)); | ||
return result; | ||
return { code: code, map: map }; | ||
}, | ||
transformBundle: function transformBundle(source) { | ||
generateStyleBundle(); | ||
var map = new MagicString(source); | ||
var result = { | ||
code: source, | ||
map: map.generateMap({ hires: true }), | ||
}; | ||
debug$1('with(this) fixed!'); | ||
return result; | ||
}, | ||
ongenerate: function ongenerate(opts, rendered) { | ||
debug$1('on generate!'); | ||
generateStyleBundle(); | ||
rendered.code = rendered.code.replace( | ||
/if[\s]*\(window\.__VUE_WITH_STATEMENT__\)/g, 'with(this)'); | ||
debug$1('with(this) fixed!'); | ||
}, | ||
ongenerate: function ongenerate() { | ||
compileStyle(styles, options); | ||
} | ||
}; | ||
} | ||
function emitted(text, bytes) { | ||
console.log(green(text), getSize(bytes)); | ||
} | ||
function green(text) { | ||
return ("\u001b[1m\u001b[32m" + text + "\u001b[39m\u001b[22m"); | ||
} | ||
function getSize(bytes) { | ||
if (bytes < 10000) { | ||
return ((bytes.toFixed(0)) + " B"); | ||
} | ||
return bytes < 1024000 | ||
? (((bytes / 1024).toPrecision(3)) + " kB'") | ||
: (((bytes / 1024 / 1024).toPrecision(4)) + " MB"); | ||
} | ||
export default vue; |
{ | ||
"name": "rollup-plugin-vue", | ||
"version": "2.2.10", | ||
"version": "2.2.11", | ||
"description": "Roll .vue files", | ||
@@ -38,4 +38,4 @@ "main": "dist/rollup-plugin-vue.common.js", | ||
"html-minifier": "^3.1.0", | ||
"magic-string": "^0.16.0", | ||
"parse5": "^2.2.2", | ||
"magic-string": "^0.19.0", | ||
"parse5": "^3.0.0", | ||
"rollup-pluginutils": "^1.5.2", | ||
@@ -51,7 +51,7 @@ "vue-template-compiler": "^2.0.3", | ||
"eslint": "^3.7.1", | ||
"eslint-config-airbnb": "^12.0.0", | ||
"eslint-config-airbnb-base": "^8.0.0", | ||
"eslint-config-airbnb": "^13.0.0", | ||
"eslint-config-airbnb-base": "^11.0.0", | ||
"eslint-plugin-html": "^1.5.3", | ||
"eslint-plugin-import": "^1.16.0", | ||
"eslint-plugin-jsx-a11y": "^2.2.3", | ||
"eslint-plugin-import": "^2.2.0", | ||
"eslint-plugin-jsx-a11y": "^3.0.1", | ||
"eslint-plugin-react": "^6.4.1", | ||
@@ -61,3 +61,3 @@ "istanbul": "^0.4.5", | ||
"mocha-lcov-reporter": "^1.2.0", | ||
"rollup": "^0.36.3", | ||
"rollup": "^0.37.0", | ||
"rollup-plugin-buble": "^0.14.0", | ||
@@ -64,0 +64,0 @@ "rollup-plugin-replace": "^1.1.1", |
@@ -159,3 +159,3 @@ # Rollup Plugin for Vue | ||
- [Rahul Kadyan][https://github.com/znck] | ||
- [Rahul Kadyan](https://github.com/znck) | ||
- [Thomas Ghysels](https://github.com/thgh) | ||
@@ -162,0 +162,0 @@ - [Eduardo San Martin Morote](https://github.com/posva) |
108
src/index.js
@@ -7,2 +7,3 @@ import { createFilter } from 'rollup-pluginutils'; | ||
import DEFAULT_OPTIONS from './options'; | ||
import compileStyle from './style'; | ||
import debug from './debug'; | ||
@@ -47,4 +48,3 @@ | ||
} | ||
} catch (e) { | ||
} | ||
} catch (e) {} | ||
/* eslint-enable */ | ||
@@ -55,60 +55,5 @@ | ||
const styles = {}; | ||
let rollupOptions; | ||
let generated = false; | ||
const generateStyleBundle = () => { | ||
if (options.css === false) { | ||
return; | ||
} | ||
if (generated) { | ||
debug('Style already generated!'); | ||
return; | ||
} | ||
generated = true; | ||
// Combine all stylesheets. | ||
let css = ''; | ||
Object.keys(styles).forEach((key) => { | ||
css += styles[key].content || ''; | ||
}); | ||
// Emit styles through callback | ||
if (typeof options.css === 'function') { | ||
options.css(css, styles); | ||
return; | ||
} | ||
// Don't generate empty style file. | ||
if (!css.trim().length) { | ||
return; | ||
} | ||
let dest = options.css; | ||
if (typeof dest !== 'string') { | ||
// Guess destination filename | ||
dest = rollupOptions.dest || 'bundle.js'; | ||
if (dest.endsWith('.js')) { | ||
dest = dest.slice(0, -3); | ||
} | ||
dest = `${dest}.css`; | ||
} | ||
// Emit styles to file | ||
writeFile(dest, css, (err) => { | ||
if (err) { | ||
throw err; | ||
} | ||
emitted(dest, css.length); | ||
}); | ||
}; | ||
return { | ||
name: 'vue', | ||
options(o) { | ||
if (rollupOptions === undefined) { | ||
rollupOptions = o; | ||
debug('Set options.'); | ||
} | ||
}, | ||
transform(source, id) { | ||
@@ -121,53 +66,16 @@ if (!filter(id) || !id.endsWith('.vue')) { | ||
debug(`Transform: ${id}`); | ||
const { js, css, map } = vueTransform(source, id, options); | ||
// Map of every stylesheet | ||
styles[id] = css || {}; | ||
const { code, css, map } = vueTransform(source, id, options); | ||
// Component javascript with inlined html template | ||
const result = { | ||
code: js, | ||
map: map.generateMap({ hires: true }), | ||
}; | ||
styles[id] = css; | ||
debug(`Transformed: ${id}`); | ||
return result; | ||
return { code, map }; | ||
}, | ||
transformBundle(source) { | ||
generateStyleBundle(); | ||
const map = new MagicString(source); | ||
const result = { | ||
code: source, | ||
map: map.generateMap({ hires: true }), | ||
}; | ||
debug('with(this) fixed!'); | ||
return result; | ||
}, | ||
ongenerate(opts, rendered) { | ||
debug('on generate!'); | ||
generateStyleBundle(); | ||
rendered.code = rendered.code.replace( | ||
/if[\s]*\(window\.__VUE_WITH_STATEMENT__\)/g, 'with(this)'); | ||
debug('with(this) fixed!'); | ||
}, | ||
ongenerate() { | ||
compileStyle(styles, options); | ||
} | ||
}; | ||
} | ||
function emitted(text, bytes) { | ||
console.log(green(text), getSize(bytes)); | ||
} | ||
function green(text) { | ||
return `\u001b[1m\u001b[32m${text}\u001b[39m\u001b[22m`; | ||
} | ||
function getSize(bytes) { | ||
if (bytes < 10000) { | ||
return `${bytes.toFixed(0)} B`; | ||
} | ||
return bytes < 1024000 | ||
? `${(bytes / 1024).toPrecision(3)} kB'` | ||
: `${(bytes / 1024 / 1024).toPrecision(4)} MB`; | ||
} |
@@ -7,2 +7,32 @@ export default { | ||
}, | ||
vue: { | ||
// Remove all trasforms added by vue since it's up to the user | ||
// to use whatever he wants | ||
// https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js#L6 | ||
transforms: { | ||
stripWith: true, // remove the with statement | ||
arrow: false, | ||
classes: false, | ||
collections: false, | ||
computedProperty: false, | ||
conciseMethodProperty: false, | ||
constLoop: false, | ||
dangerousForOf: false, | ||
dangerousTaggedTemplateString: false, | ||
defaultParameter: false, | ||
destructuring: false, | ||
forOf: false, | ||
generator: false, | ||
letConst: false, | ||
modules: false, | ||
numericLiteral: false, | ||
parameterDestructuring: false, | ||
reservedProperties: false, | ||
spreadRest: false, | ||
stickyRegExp: false, | ||
templateString: false, | ||
unicodeRegExp: false, | ||
}, | ||
} | ||
}; |
@@ -10,17 +10,14 @@ import deIndent from 'de-indent'; | ||
/** | ||
* Check the lang attribute of a parse5 node. | ||
* | ||
* @param {Node|*} node | ||
* @return {String|undefined} | ||
*/ | ||
function checkLang(node) { | ||
if (node.attrs) { | ||
for (const attr of node.attrs) { | ||
if (attr.name === 'lang') { | ||
return attr.value; | ||
} | ||
} | ||
function getNodeAttrs(node) { | ||
if (node.attrs) { | ||
const attributes = {}; | ||
for (const attr of node.attrs) { | ||
attributes[attr.name] = attr.value; | ||
} | ||
return undefined; | ||
return attributes; | ||
} | ||
return {}; | ||
} | ||
@@ -30,5 +27,2 @@ | ||
* Pad content with empty lines to get correct line number in errors. | ||
* | ||
* @param content | ||
* @returns {string} | ||
*/ | ||
@@ -45,5 +39,2 @@ function padContent(content) { | ||
* This is necessary for Vue 2 template compilation | ||
* | ||
* @param {string} code | ||
* @returns {string} | ||
*/ | ||
@@ -54,38 +45,19 @@ function wrapRenderFunction(code) { | ||
/** | ||
* Only support for es5 modules | ||
* | ||
* @param script | ||
* @param render | ||
* @param lang | ||
* @returns {string} | ||
*/ | ||
function injectRender(script, render, lang) { | ||
function injectRender(script, render, lang, options) { | ||
if (['js', 'babel'].indexOf(lang.toLowerCase()) > -1) { | ||
const matches = /(export default[^{]*\{)/g.exec(script); | ||
if (matches) { | ||
const scriptWithRender = script.split(matches[1]) | ||
// buble doesn't support export default, not even with the | ||
// module: false trasforms: | ||
// https://buble.surge.sh/guide/#using-es-modules | ||
.join('module.exports={' + | ||
`render: ${wrapRenderFunction(render.render)},` + | ||
'staticRenderFns: [' + | ||
`${render.staticRenderFns.map(wrapRenderFunction).join(',')}],` | ||
); | ||
return transpileVueTemplate(scriptWithRender, { | ||
// Remove all trasforms added by vue since it's up to the user | ||
// to use whatever he wants | ||
// https://github.com/vuejs/vue-template-es2015-compiler/blob/master/index.js#L6 | ||
transforms: { | ||
templateString: false, | ||
conciseMethodProperty: false, | ||
stripWith: true, // remove the with statement | ||
computedProperty: false, | ||
}, | ||
// put back the export default { | ||
}).replace('module.exports={', 'export default {'); | ||
const renderScript = transpileVueTemplate('module.exports={' + | ||
`render: ${wrapRenderFunction(render.render)},` + | ||
'staticRenderFns: [' + | ||
`${render.staticRenderFns.map(wrapRenderFunction).join(',')}],}`, options.vue); | ||
const result = script.split(matches[1]) | ||
.join(renderScript.replace('module.exports={', 'export default {').replace(/\}$/, '')); | ||
return result; | ||
} | ||
debug(`No injection location found in: \n${script}\n`); | ||
} else if (options.inject) { | ||
return options.inject(script, render, lang, options); | ||
} | ||
@@ -101,3 +73,5 @@ throw new Error('[rollup-plugin-vue] could not find place to inject template in script.'); | ||
*/ | ||
function injectTemplate(script, template, lang) { | ||
function injectTemplate(script, template, lang, options) { | ||
if (template === undefined) return script; | ||
if (['js', 'babel'].indexOf(lang.toLowerCase()) > -1) { | ||
@@ -111,3 +85,6 @@ const matches = /(export default[^{]*\{)/g.exec(script); | ||
debug(`No injection location found in: \n${script}\n`); | ||
} else if (options.inject) { | ||
return options.inject(script, template, lang, options); | ||
} | ||
throw new Error('[rollup-plugin-vue] could not find place to inject template in script.'); | ||
@@ -118,12 +95,11 @@ } | ||
* Compile template: DeIndent and minify html. | ||
* @param {Node} node | ||
* @param {string} filePath | ||
* @param {string} content | ||
* @param {*} options | ||
*/ | ||
function processTemplate(node, filePath, content, options) { | ||
node = node.content; | ||
const warnings = validateTemplate(node, content); | ||
function processTemplate(source, id, content, options) { | ||
if (source === undefined) return undefined; | ||
const {node, code} = source; | ||
const warnings = validateTemplate(code, content); | ||
if (warnings) { | ||
const relativePath = relative(process.cwd(), filePath); | ||
const relativePath = relative(process.cwd(), id); | ||
warnings.forEach((msg) => { | ||
@@ -135,4 +111,4 @@ console.warn(`\n Warning in ${relativePath}:\n ${msg}`); | ||
/* eslint-disable no-underscore-dangle */ | ||
const start = node.childNodes[0].__location.startOffset; | ||
const end = node.childNodes[node.childNodes.length - 1].__location.endOffset; | ||
const start = node.content.childNodes[0].__location.startOffset; | ||
const end = node.content.childNodes[node.content.childNodes.length - 1].__location.endOffset; | ||
const template = deIndent(content.slice(start, end)); | ||
@@ -144,75 +120,62 @@ /* eslint-enable no-underscore-dangle */ | ||
/** | ||
* @param {Node|ASTNode} node | ||
* @param {string} filePath | ||
* @param {string} content | ||
* @param templateOrRender | ||
*/ | ||
function processScript(node, filePath, content, templateOrRender) { | ||
const lang = checkLang(node) || 'js'; | ||
const { template, render } = templateOrRender; | ||
let script = parse5.serialize(node); | ||
function processScript(source, id, content, options, nodes) { | ||
const template = processTemplate(nodes.template[0], id, content, options, nodes); | ||
// 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; | ||
const lang = source.attrs.lang || 'js'; | ||
const map = new MagicString(script); | ||
const script = deIndent(padContent(content.slice(0, content.indexOf(source.code))) + source.code); | ||
const map = (new MagicString(script)).generateMap({ hires: true }); | ||
if (template) { | ||
script = injectTemplate(script, template, lang); | ||
} else if (render) { | ||
script = injectRender(script, render, lang); | ||
if (options.compileTemplate) { | ||
const render = require('vue-template-compiler').compile(template); | ||
return { map, code: injectRender(script, render, lang, options) }; | ||
} else { | ||
debug('Nothing to inject!'); | ||
return { map, code: injectTemplate(script, template, lang, options) }; | ||
} | ||
} | ||
script = deIndent(script); | ||
return { | ||
code: script, | ||
map, | ||
}; | ||
function processStyle(styles, id) { | ||
return styles.map(style => ({ | ||
id, | ||
code: deIndent(style.code).trim(), | ||
lang: style.attrs.lang || 'css', | ||
})); | ||
} | ||
export default function vueTransform(code, filePath, options) { | ||
// 1. Parse the file into an HTML tree | ||
const fragment = parse5.parseFragment(code, { locationInfo: true }); | ||
function parseTemplate(code) { | ||
const fragment = parse5.parseFragment(code, { locationInfo: true }); | ||
// 2. Walk through the top level nodes and check for their types | ||
const nodes = {}; | ||
for (let i = fragment.childNodes.length - 1; i >= 0; i -= 1) { | ||
nodes[fragment.childNodes[i].nodeName] = fragment.childNodes[i]; | ||
} | ||
const nodes = { | ||
template: [], | ||
script: [], | ||
style: [], | ||
}; | ||
// 3. Don't touch files that don't look like Vue components | ||
if (!nodes.script) { | ||
throw new Error('There must be at least one script tag or one' + | ||
' template tag per *.vue file.'); | ||
} | ||
for (let i = fragment.childNodes.length - 1; i >= 0; i -= 1) { | ||
const name = fragment.childNodes[i].nodeName; | ||
if (! (name in nodes)) { | ||
nodes[name] = []; | ||
} | ||
nodes[name].push({ | ||
node: fragment.childNodes[i], | ||
code: parse5.serialize(fragment.childNodes[i]), | ||
attrs: getNodeAttrs(fragment.childNodes[i]), | ||
}); | ||
} | ||
// 4. Process template | ||
const template = nodes.template | ||
? processTemplate(nodes.template, filePath, code, options) | ||
: undefined; | ||
let js; | ||
if (options.compileTemplate) { | ||
/* eslint-disable */ | ||
const render = template ? require('vue-template-compiler').compile(template) : undefined; | ||
/* eslint-enable */ | ||
js = processScript(nodes.script, filePath, code, { render }); | ||
} else { | ||
js = processScript(nodes.script, filePath, code, { template }); | ||
} | ||
if (nodes.script.length === 0) { | ||
throw new Error('There must be at least one script tag or one' + | ||
' template tag per *.vue file.'); | ||
} | ||
// 5. Process script & style | ||
return { | ||
js: js.code, | ||
map: js.map, | ||
css: nodes.style && { | ||
content: parse5.serialize(nodes.style), | ||
lang: checkLang(nodes.style), | ||
}, | ||
}; | ||
return nodes; | ||
} | ||
export default function vueTransform(code, id, options) { | ||
const nodes = parseTemplate(code); | ||
const js = processScript(nodes.script[0], id, code, options, nodes); | ||
const css = processStyle(nodes.style, id, code, options, nodes); | ||
return { css, code: js.code, map: js.map }; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
11
37251
820
+ Added@types/node@22.9.0(transitive)
+ Addedmagic-string@0.19.1(transitive)
+ Addedparse5@3.0.3(transitive)
+ Addedundici-types@6.19.8(transitive)
- Removedmagic-string@0.16.0(transitive)
Updatedmagic-string@^0.19.0
Updatedparse5@^3.0.0