move declaration adding logic to ssr/dom generators

pull/1721/head
Rich Harris 7 years ago
parent 1c821c5953
commit d18a3189e9

@ -34,6 +34,13 @@ interface Computation {
hasRestParam: boolean; hasRestParam: boolean;
} }
interface Declaration {
type: string;
name: string;
node: Node;
block: string;
}
function detectIndentation(str: string) { function detectIndentation(str: string) {
const pattern = /^[\t\s]{1,4}/gm; const pattern = /^[\t\s]{1,4}/gm;
let match; let match;
@ -118,7 +125,7 @@ export default class Component {
computations: Computation[]; computations: Computation[];
templateProperties: Record<string, Node>; templateProperties: Record<string, Node>;
slots: Set<string>; slots: Set<string>;
javascript: string; javascript: [string, string];
used: { used: {
components: Set<string>; components: Set<string>;
@ -129,6 +136,8 @@ export default class Component {
actions: Set<string>; actions: Set<string>;
}; };
declarations: Declaration[];
refCallees: Node[]; refCallees: Node[];
code: MagicString; code: MagicString;
@ -190,6 +199,8 @@ export default class Component {
actions: new Set(), actions: new Set(),
}; };
this.declarations = [];
this.refs = new Set(); this.refs = new Set();
this.refCallees = []; this.refCallees = [];
@ -561,7 +572,7 @@ export default class Component {
}); });
} }
processDefaultExport(node, componentDefinition, indentExclusionRanges) { processDefaultExport(node, indentExclusionRanges) {
const { templateProperties, source, code } = this; const { templateProperties, source, code } = this;
if (node.declaration.type !== 'ObjectExpression') { if (node.declaration.type !== 'ObjectExpression') {
@ -627,7 +638,7 @@ export default class Component {
} }
}); });
const addArrowFunctionExpression = (name: string, node: Node) => { const addArrowFunctionExpression = (type: string, name: string, node: Node) => {
const { body, params, async } = node; const { body, params, async } = node;
const fnKeyword = async ? 'async function' : 'function'; const fnKeyword = async ? 'async function' : 'function';
@ -635,37 +646,43 @@ export default class Component {
`[✂${params[0].start}-${params[params.length - 1].end}✂]` : `[✂${params[0].start}-${params[params.length - 1].end}✂]` :
``; ``;
if (body.type === 'BlockStatement') { const block = body.type === 'BlockStatement'
componentDefinition.addBlock(deindent` ? deindent`
${fnKeyword} ${name}(${paramString}) [${body.start}-${body.end}] ${fnKeyword} ${name}(${paramString}) [${body.start}-${body.end}]
`); `
} else { : deindent`
componentDefinition.addBlock(deindent`
${fnKeyword} ${name}(${paramString}) { ${fnKeyword} ${name}(${paramString}) {
return [${body.start}-${body.end}]; return [${body.start}-${body.end}];
} }
`); `;
}
this.declarations.push({ type, name, block, node });
}; };
const addFunctionExpression = (name: string, node: Node) => { const addFunctionExpression = (type: string, name: string, node: Node) => {
const { async } = node; const { async } = node;
const fnKeyword = async ? 'async function' : 'function'; const fnKeyword = async ? 'async function' : 'function';
let c = node.start; let c = node.start;
while (this.source[c] !== '(') c += 1; while (this.source[c] !== '(') c += 1;
componentDefinition.addBlock(deindent`
const block = deindent`
${fnKeyword} ${name}[${c}-${node.end}]; ${fnKeyword} ${name}[${c}-${node.end}];
`); `;
this.declarations.push({ type, name, block, node });
}; };
const addValue = (name: string, node: Node) => { const addValue = (type: string, name: string, node: Node) => {
componentDefinition.addBlock(deindent` const block = deindent`
var ${name} = [${node.start}-${node.end}]; var ${name} = [${node.start}-${node.end}];
`); `;
this.declarations.push({ type, name, block, node });
}; };
const addDeclaration = ( const addDeclaration = (
type: string,
key: string, key: string,
node: Node, node: Node,
allowShorthandImport?: boolean, allowShorthandImport?: boolean,
@ -697,17 +714,17 @@ export default class Component {
} }
if (node.type === 'ArrowFunctionExpression') { if (node.type === 'ArrowFunctionExpression') {
addArrowFunctionExpression(name, node); addArrowFunctionExpression(type, name, node);
} else if (node.type === 'FunctionExpression') { } else if (node.type === 'FunctionExpression') {
addFunctionExpression(name, node); addFunctionExpression(type, name, node);
} else { } else {
addValue(name, node); addValue(type, name, node);
} }
}; };
if (templateProperties.components) { if (templateProperties.components) {
templateProperties.components.value.properties.forEach((property: Node) => { templateProperties.components.value.properties.forEach((property: Node) => {
addDeclaration(getName(property.key), property.value, true, 'components'); addDeclaration('components', getName(property.key), property.value, true, 'components');
}); });
} }
@ -720,7 +737,7 @@ export default class Component {
const key = getName(prop.key); const key = getName(prop.key);
const value = prop.value; const value = prop.value;
addDeclaration(key, value, false, 'computed', { addDeclaration('computed', key, value, false, 'computed', {
state: true, state: true,
changed: true changed: true
}); });
@ -770,23 +787,23 @@ export default class Component {
} }
if (templateProperties.data) { if (templateProperties.data) {
addDeclaration('data', templateProperties.data.value); addDeclaration('data', 'data', templateProperties.data.value);
} }
if (templateProperties.events) { if (templateProperties.events) {
templateProperties.events.value.properties.forEach((property: Node) => { templateProperties.events.value.properties.forEach((property: Node) => {
addDeclaration(getName(property.key), property.value, false, 'events'); addDeclaration('events', getName(property.key), property.value, false, 'events');
}); });
} }
if (templateProperties.helpers) { if (templateProperties.helpers) {
templateProperties.helpers.value.properties.forEach((property: Node) => { templateProperties.helpers.value.properties.forEach((property: Node) => {
addDeclaration(getName(property.key), property.value, false, 'helpers'); addDeclaration('helpers', getName(property.key), property.value, false, 'helpers');
}); });
} }
if (templateProperties.methods) { if (templateProperties.methods) {
addDeclaration('methods', templateProperties.methods.value); addDeclaration('methods', 'methods', templateProperties.methods.value);
templateProperties.methods.value.properties.forEach(property => { templateProperties.methods.value.properties.forEach(property => {
this.methods.add(getName(property.key)); this.methods.add(getName(property.key));
@ -799,23 +816,23 @@ export default class Component {
} }
if (templateProperties.oncreate) { if (templateProperties.oncreate) {
addDeclaration('oncreate', templateProperties.oncreate.value); addDeclaration('oncreate', 'oncreate', templateProperties.oncreate.value);
} }
if (templateProperties.ondestroy) { if (templateProperties.ondestroy) {
addDeclaration('ondestroy', templateProperties.ondestroy.value); addDeclaration('ondestroy', 'ondestroy', templateProperties.ondestroy.value);
} }
if (templateProperties.onstate) { if (templateProperties.onstate) {
addDeclaration('onstate', templateProperties.onstate.value); addDeclaration('onstate', 'onstate', templateProperties.onstate.value);
} }
if (templateProperties.onupdate) { if (templateProperties.onupdate) {
addDeclaration('onupdate', templateProperties.onupdate.value); addDeclaration('onupdate', 'onupdate', templateProperties.onupdate.value);
} }
if (templateProperties.preload) { if (templateProperties.preload) {
addDeclaration('preload', templateProperties.preload.value); addDeclaration('preload', 'preload', templateProperties.preload.value);
} }
if (templateProperties.props) { if (templateProperties.props) {
@ -823,11 +840,11 @@ export default class Component {
} }
if (templateProperties.setup) { if (templateProperties.setup) {
addDeclaration('setup', templateProperties.setup.value); addDeclaration('setup', 'setup', templateProperties.setup.value);
} }
if (templateProperties.store) { if (templateProperties.store) {
addDeclaration('store', templateProperties.store.value); addDeclaration('store', 'store', templateProperties.store.value);
} }
if (templateProperties.tag) { if (templateProperties.tag) {
@ -836,19 +853,19 @@ export default class Component {
if (templateProperties.transitions) { if (templateProperties.transitions) {
templateProperties.transitions.value.properties.forEach((property: Node) => { templateProperties.transitions.value.properties.forEach((property: Node) => {
addDeclaration(getName(property.key), property.value, false, 'transitions'); addDeclaration('transitions', getName(property.key), property.value, false, 'transitions');
}); });
} }
if (templateProperties.animations) { if (templateProperties.animations) {
templateProperties.animations.value.properties.forEach((property: Node) => { templateProperties.animations.value.properties.forEach((property: Node) => {
addDeclaration(getName(property.key), property.value, false, 'animations'); addDeclaration('animations', getName(property.key), property.value, false, 'animations');
}); });
} }
if (templateProperties.actions) { if (templateProperties.actions) {
templateProperties.actions.value.properties.forEach((property: Node) => { templateProperties.actions.value.properties.forEach((property: Node) => {
addDeclaration(getName(property.key), property.value, false, 'actions'); addDeclaration('actions', getName(property.key), property.value, false, 'actions');
}); });
} }
@ -856,19 +873,13 @@ export default class Component {
} }
walkJs() { walkJs() {
const {
code,
source,
imports
} = this;
const { js } = this.ast; const { js } = this.ast;
if (!js) return;
const componentDefinition = new CodeBuilder();
if (js) {
this.addSourcemapLocations(js.content); this.addSourcemapLocations(js.content);
const { code, source, imports } = this;
const indentationLevel = getIndentationLevel(source, js.content.body[0].start); const indentationLevel = getIndentationLevel(source, js.content.body[0].start);
const indentExclusionRanges = getIndentExclusionRanges(js.content); const indentExclusionRanges = getIndentExclusionRanges(js.content);
@ -894,7 +905,7 @@ export default class Component {
} }
if (node.type === 'ExportDefaultDeclaration') { if (node.type === 'ExportDefaultDeclaration') {
this.processDefaultExport(node, componentDefinition, indentExclusionRanges); this.processDefaultExport(node, indentExclusionRanges);
} }
// imports need to be hoisted out of the IIFE // imports need to be hoisted out of the IIFE
@ -923,14 +934,14 @@ export default class Component {
let b = js.content.end; let b = js.content.end;
while (/\s/.test(source[b - 1])) b -= 1; while (/\s/.test(source[b - 1])) b -= 1;
if (this.defaultExport) { this.javascript = this.defaultExport
this.javascript = ''; ? [
if (a !== this.defaultExport.start) this.javascript += `[✂${a}-${this.defaultExport.start}✂]`; a !== this.defaultExport.start ? `[✂${a}-${this.defaultExport.start}✂]` : '',
if (!componentDefinition.isEmpty()) this.javascript += componentDefinition; b !== this.defaultExport.end ?`[✂${this.defaultExport.end}-${b}✂]` : ''
if (this.defaultExport.end !== b) this.javascript += `[✂${this.defaultExport.end}-${b}]`; ]
} else { : [
this.javascript = a === b ? null : `[✂${a}-${b}✂]`; a !== b ? `[✂${a}-${b}✂]` : '',
} ''
} ];
} }
} }

@ -83,7 +83,18 @@ export default function dom(
} }
if (component.javascript) { if (component.javascript) {
builder.addBlock(component.javascript); const componentDefinition = new CodeBuilder();
component.declarations.forEach(declaration => {
componentDefinition.addBlock(declaration.block);
});
const js = (
component.javascript[0] +
componentDefinition +
component.javascript[1]
);
builder.addBlock(js);
} }
if (component.options.dev) { if (component.options.dev) {

@ -1,13 +1,10 @@
import deindent from '../../utils/deindent'; import deindent from '../../utils/deindent';
import Component from '../Component'; import Component from '../Component';
import Stats from '../../Stats';
import Stylesheet from '../../css/Stylesheet';
import { removeNode, removeObjectKey } from '../../utils/removeNode';
import getName from '../../utils/getName';
import globalWhitelist from '../../utils/globalWhitelist'; import globalWhitelist from '../../utils/globalWhitelist';
import { Ast, Node, CompileOptions } from '../../interfaces'; import { Node, CompileOptions } from '../../interfaces';
import { AppendTarget } from '../../interfaces'; import { AppendTarget } from '../../interfaces';
import { stringify } from '../../utils/stringify'; import { stringify } from '../../utils/stringify';
import CodeBuilder from '../../utils/CodeBuilder';
export class SsrTarget { export class SsrTarget {
bindings: string[]; bindings: string[];
@ -71,11 +68,36 @@ export default function ssr(
initialState.push('ctx'); initialState.push('ctx');
const helpers = new Set(); let js = null;
if (component.javascript) {
const componentDefinition = new CodeBuilder();
// not all properties are relevant to SSR (e.g. lifecycle hooks)
const relevant = new Set([
'data',
'components',
'computed',
'helpers',
'preload',
'store'
]);
component.declarations.forEach(declaration => {
if (relevant.has(declaration.type)) {
componentDefinition.addBlock(declaration.block);
}
});
js = (
component.javascript[0] +
componentDefinition +
component.javascript[1]
);
}
// TODO concatenate CSS maps // TODO concatenate CSS maps
const result = deindent` const result = (deindent`
${component.javascript} ${js}
var ${name} = {}; var ${name} = {};
@ -140,7 +162,7 @@ export default function ssr(
var warned = false; var warned = false;
${templateProperties.preload && `${name}.preload = %preload;`} ${templateProperties.preload && `${name}.preload = %preload;`}
`; `).trim();
return component.generate(result, options, { name, format }); return component.generate(result, options, { name, format });
} }

Loading…
Cancel
Save