Skip to content

Instantly share code, notes, and snippets.

@sliekens
Created December 30, 2018 19:31
Show Gist options
  • Save sliekens/350198fe025787d451f3fd16ca5f87f1 to your computer and use it in GitHub Desktop.
Save sliekens/350198fe025787d451f3fd16ca5f87f1 to your computer and use it in GitHub Desktop.
rollup-plugin-vue-unofficial
import { Plugin, PluginContext } from 'rollup';
import { createFilter } from 'rollup-pluginutils';
import {
parse,
compileTemplate,
TemplateCompileResult
} from '@vue/component-compiler-utils';
import { VueTemplateCompiler } from '@vue/component-compiler-utils/dist/types';
import {
ObjectExpression,
BlockStatement,
ArrayExpression,
Program
} from 'estree';
const templateCompiler = require('vue-template-compiler') as VueTemplateCompiler;
import * as estraverse from 'estraverse';
import * as escodegen from 'escodegen';
export interface Options {
optimize?: boolean;
include?: string | string[];
exclude?: string | string[];
}
export const defaultOptions: Options = {
include: '**/*.vue',
optimize: false
};
function nullRender(): BlockStatement {
return {
type: 'BlockStatement',
body: []
};
}
function nullStaticRender(): ArrayExpression {
return {
type: 'ArrayExpression',
elements: []
};
}
export default function(options: Options = {}): Plugin {
options = { ...defaultOptions, ...options };
const filter = createFilter(options.include, options.exclude);
function decompileTemplate(
context: PluginContext,
result: TemplateCompileResult
) {
let renderfn: BlockStatement | null = null;
let staticRenderFns: ArrayExpression | null = null;
let ast = context.parse(result.code, {});
estraverse.traverse(ast, {
enter(node, parentNode) {
if (node.type === 'FunctionExpression') {
return estraverse.VisitorOption.Skip;
}
if (node.type === 'VariableDeclarator') {
if (
node.id.type === 'Identifier' &&
node.id.name === 'render'
) {
if (node.init == null) {
throw new Error(`Missing value for 'render'.`);
} else if (node.init.type !== 'FunctionExpression') {
throw new Error(
`The value of 'render' is not a function.`
);
} else {
renderfn = node.init.body;
}
}
if (
node.id.type === 'Identifier' &&
node.id.name === 'staticRenderFns'
) {
if (node.init == null) {
throw new Error(
`Missing value for 'staticRenderFns'.`
);
} else if (node.init.type !== 'ArrayExpression') {
throw new Error(
`The value of 'staticRenderFns' is not an array.`
);
} else {
staticRenderFns = node.init;
}
return estraverse.VisitorOption.Break;
}
}
}
});
return {
render: renderfn!,
staticRender: staticRenderFns!
};
}
return {
name: 'rollup-plugin-vue-unofficial',
transform(code, id) {
if (!filter(id)) {
return;
}
let sfcDescriptor = parse({
compiler: templateCompiler,
source: code,
filename: id,
needMap: true
});
let render: BlockStatement = nullRender();
let staticRender: ArrayExpression = nullStaticRender();
if (sfcDescriptor.template !== null) {
let compiledTemplate = compileTemplate({
source: sfcDescriptor.template.content,
filename: id,
compiler: templateCompiler,
isProduction: options.optimize
});
let parsed = decompileTemplate(this, compiledTemplate);
render = parsed.render;
staticRender = parsed.staticRender;
}
let ast: Program;
if (sfcDescriptor.script !== null) {
ast = this.parse(sfcDescriptor.script.content, {});
} else {
ast = this.parse(`export default {}`, {});
}
// TODO: consider skipping if obj already has render()
estraverse.replace(ast, {
enter(node, parentNode) {
if (
node.type === 'ObjectExpression' &&
parentNode!.type === 'ExportDefaultDeclaration'
) {
return <ObjectExpression>{
type: 'ObjectExpression',
properties: [
...node.properties,
{
type: 'Property',
method: true,
shorthand: false,
computed: false,
key: {
type: 'Identifier',
name: 'render'
},
kind: 'init',
value: {
type: 'FunctionExpression',
params: [],
body: render
}
},
{
type: 'Property',
method: false,
shorthand: false,
computed: false,
key: {
type: 'Identifier',
name: 'staticRenderFns'
},
kind: 'init',
value: staticRender
}
]
};
}
}
});
return { code: escodegen.generate(ast) };
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment