Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import globals from internals #2963

Merged
merged 10 commits into from
Jun 24, 2019
41 changes: 28 additions & 13 deletions src/compiler/compile/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ export default class Component {
reactive_declaration_nodes: Set<Node> = new Set();
has_reactive_assignments = false;
injected_reactive_declaration_vars: Set<string> = new Set();
helpers: Set<string> = new Set();
helpers: Map<string, string> = new Map();
globals: Map<string, string> = new Map();

indirect_dependencies: Map<string, Set<string>> = new Map();

Expand Down Expand Up @@ -233,8 +234,15 @@ export default class Component {
}

helper(name: string) {
this.helpers.add(name);
return this.alias(name);
const alias = this.alias(name)
this.helpers.set(name, alias);
return alias;
}

global(name: string) {
const alias = this.alias(name);
this.globals.set(name, alias);
return alias;
}

generate(result: string) {
Expand All @@ -251,23 +259,29 @@ export default class Component {
.replace(/__svelte:self__/g, this.name)
.replace(compile_options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (_match: string, sigil: string, name: string) => {
if (sigil === '@') {
if (internal_exports.has(name)) {
if (compile_options.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
this.helpers.add(name);
if (name[0] === '_') {
return this.global(name.slice(1));
}

if (!internal_exports.has(name)) {
throw new Error(`compiler error: this shouldn't happen! generated code is trying to use inexistent internal '${name}'`);
}

if (compile_options.dev && internal_exports.has(`${name}Dev`)) {
name = `${name}Dev`;
}

return this.alias(name);
return this.helper(name);
}

return sigil.slice(1) + name;
});

const imported_helpers = Array.from(this.helpers)
.sort()
.map(name => {
const alias = this.alias(name);
return { name, alias };
});
const referenced_globals = Array.from(this.globals, ([name, alias]) => name !== alias && ({ name, alias })).filter(Boolean);
if (referenced_globals.length) {
this.helper('globals');
}
const imported_helpers = Array.from(this.helpers, ([name, alias]) => ({ name, alias }));

const module = create_module(
result,
Expand All @@ -276,6 +290,7 @@ export default class Component {
banner,
compile_options.sveltePath,
imported_helpers,
referenced_globals,
this.imports,
this.vars.filter(variable => variable.module && variable.export_name).map(variable => ({
name: variable.name,
Expand Down
15 changes: 13 additions & 2 deletions src/compiler/compile/create_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ export default function create_module(
banner: string,
sveltePath = 'svelte',
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[],
source: string
): string {
const internal_path = `${sveltePath}/internal`;

if (format === 'esm') {
return esm(code, name, banner, sveltePath, internal_path, helpers, imports, module_exports, source);
return esm(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports, source);
}

if (format === 'cjs') return cjs(code, name, banner, sveltePath, internal_path, helpers, imports, module_exports);
if (format === 'cjs') return cjs(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);

throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`);
}
Expand All @@ -45,13 +46,17 @@ function esm(
sveltePath: string,
internal_path: string,
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[],
source: string
) {
const internal_imports = helpers.length > 0 && (
`import ${stringify_props(helpers.map(h => h.name === h.alias ? h.name : `${h.name} as ${h.alias}`).sort())} from ${JSON.stringify(internal_path)};`
);
const internal_globals = globals.length > 0 && (
`const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};`
);

const user_imports = imports.length > 0 && (
imports
Expand All @@ -70,6 +75,7 @@ function esm(
return deindent`
${banner}
${internal_imports}
${internal_globals}
${user_imports}

${code}
Expand All @@ -85,6 +91,7 @@ function cjs(
sveltePath: string,
internal_path: string,
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[]
) {
Expand All @@ -93,6 +100,9 @@ function cjs(
const internal_imports = helpers.length > 0 && (
`const ${stringify_props(declarations)} = require(${JSON.stringify(internal_path)});\n`
);
const internal_globals = globals.length > 0 && (
`const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};`
);

const requires = imports.map(node => {
let lhs;
Expand Down Expand Up @@ -127,6 +137,7 @@ function cjs(
"use strict";

${internal_imports}
${internal_globals}
${requires}

${code}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/compile/render-dom/Block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export default class Block {

if (parent_node) {
this.builders.mount.add_line(`@append(${parent_node}, ${name});`);
if (parent_node === 'document.head' && !no_detach) this.builders.destroy.add_line(`@detach(${name});`);
if (parent_node === '@_document.head' && !no_detach) this.builders.destroy.add_line(`@detach(${name});`);
} else {
this.builders.mount.add_line(`@insert(#target, ${name}, anchor);`);
if (!no_detach) this.builders.destroy.add_conditional('detaching', `@detach(${name});`);
Expand Down
22 changes: 12 additions & 10 deletions src/compiler/compile/render-dom/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ export default function dom(
`${css.code}\n/*# sourceMappingURL=${css.map.toUrl()} */` :
css.code, { only_escape_at_symbol: true });

const add_css = component.get_unique_name('add_css');

if (styles && component.compile_options.css !== false && !options.customElement) {
builder.add_block(deindent`
function @add_css() {
function ${add_css}() {
var style = @element("style");
style.id = '${component.stylesheet.id}-style';
style.textContent = ${styles};
@append(document.head, style);
@append(@_document.head, style);
}
`);
}
Expand All @@ -57,7 +59,7 @@ export default function dom(

if (options.dev && !options.hydratable) {
block.builders.claim.add_line(
'throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");'
'throw new @_Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");'
);
}

Expand Down Expand Up @@ -106,7 +108,7 @@ export default function dom(
} else if (component.compile_options.dev) {
body.push(deindent`
get ${x.export_name}() {
throw new Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
throw new @_Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
`);
}
Expand All @@ -122,14 +124,14 @@ export default function dom(
} else if (component.compile_options.dev) {
body.push(deindent`
set ${x.export_name}(value) {
throw new Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'");
throw new @_Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'");
}
`);
}
} else if (component.compile_options.dev) {
body.push(deindent`
set ${x.export_name}(value) {
throw new Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
throw new @_Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
`);
}
Expand All @@ -145,7 +147,7 @@ export default function dom(
const props = ${options.customElement ? `this.attributes` : `options.props || {}`};
${expected.map(prop => deindent`
if (ctx.${prop.name} === undefined && !('${prop.export_name}' in props)) {
console.warn("<${component.tag}> was created without expected prop '${prop.export_name}'");
@_console.warn("<${component.tag}> was created without expected prop '${prop.export_name}'");
}`)}
`;
}
Expand Down Expand Up @@ -402,7 +404,7 @@ export default function dom(
if (component.compile_options.dev && !component.var_lookup.has('$$props') && writable_props.length) {
unknown_props_check = deindent`
const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}];
Object.keys($$props).forEach(key => {
@_Object.keys($$props).forEach(key => {
if (!writable_props.includes(key) && !key.startsWith('$$')) console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`);
});
`;
Expand Down Expand Up @@ -481,7 +483,7 @@ export default function dom(

if (component.tag != null) {
builder.add_block(deindent`
customElements.define("${component.tag}", ${name});
@_customElements.define("${component.tag}", ${name});
`);
}
} else {
Expand All @@ -491,7 +493,7 @@ export default function dom(
class ${name} extends @${superclass} {
constructor(options) {
super(${options.dev && `options`});
${should_add_css && `if (!document.getElementById("${component.stylesheet.id}-style")) @add_css();`}
${should_add_css && `if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`}
@init(this, options, ${definition}, create_fragment, ${not_equal}, ${prop_names});

${dev_props_check}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/compile/render-dom/wrappers/AwaitBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export default class AwaitBlockWrapper extends Wrapper {
this.catch.block.name && `catch: ${this.catch.block.name}`,
this.then.block.name && `value: '${this.node.value}'`,
this.catch.block.name && `error: '${this.node.error}'`,
this.pending.block.has_outro_method && `blocks: Array(3)`
this.pending.block.has_outro_method && `blocks: [,,,]`
].filter(Boolean);

block.builders.init.add_block(deindent`
Expand Down Expand Up @@ -230,4 +230,4 @@ export default class AwaitBlockWrapper extends Wrapper {
branch.fragment.render(branch.block, null, 'nodes');
});
}
}
}
4 changes: 2 additions & 2 deletions src/compiler/compile/render-dom/wrappers/Body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ export default class BodyWrapper extends Wrapper {
const snippet = handler.render(block);

block.builders.init.add_block(deindent`
document.body.addEventListener("${handler.name}", ${snippet});
@_document.body.addEventListener("${handler.name}", ${snippet});
`);

block.builders.destroy.add_block(deindent`
document.body.removeEventListener("${handler.name}", ${snippet});
@_document.body.removeEventListener("${handler.name}", ${snippet});
`);
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/compile/render-dom/wrappers/DebugTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ export default class DebugTagWrapper extends Wrapper {
block.builders.update.add_block(deindent`
if (${condition}) {
const { ${ctx_identifiers} } = ctx;
console.${log}({ ${logged_identifiers} });
@_console.${log}({ ${logged_identifiers} });
debugger;
}
`);

block.builders.create.add_block(deindent`
{
const { ${ctx_identifiers} } = ctx;
console.${log}({ ${logged_identifiers} });
@_console.${log}({ ${logged_identifiers} });
debugger;
}
`);
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/compile/render-dom/wrappers/EachBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export default class EachBlockWrapper extends Wrapper {

renderer.blocks.push(deindent`
function ${this.vars.get_each_context}(ctx, list, i) {
const child_ctx = Object.create(ctx);
const child_ctx = @_Object.create(ctx);
${this.context_props}
return child_ctx;
}
Expand Down Expand Up @@ -296,7 +296,7 @@ export default class EachBlockWrapper extends Wrapper {
const lookup = block.get_unique_name(`${this.var}_lookup`);

block.add_variable(iterations, '[]');
block.add_variable(lookup, `new Map()`);
block.add_variable(lookup, `new @_Map()`);

if (this.fragment.nodes[0].is_dom_node()) {
this.block.first = this.fragment.nodes[0].var;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export default class BindingWrapper {
case 'currentTime':
case 'playbackRate':
case 'volume':
update_conditions.push(`!isNaN(${this.snippet})`);
update_conditions.push(`!@_isNaN(${this.snippet})`);
break;

case 'paused':
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/compile/render-dom/wrappers/Element/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ export default class ElementWrapper extends Wrapper {
`@append(${parent_node}, ${node});`
);

if (parent_node === 'document.head') {
if (parent_node === '@_document.head') {
block.builders.destroy.add_line(`@detach(${node});`);
}
} else {
Expand Down Expand Up @@ -379,7 +379,7 @@ export default class ElementWrapper extends Wrapper {
}

if (namespace) {
return `document.createElementNS("${namespace}", "${name}")`;
return `@_document.createElementNS("${namespace}", "${name}")`;
}

return `@element("${name}")`;
Expand Down Expand Up @@ -465,7 +465,7 @@ export default class ElementWrapper extends Wrapper {
block.builders.init.add_block(deindent`
function ${handler}() {
${animation_frame && deindent`
cancelAnimationFrame(${animation_frame});
@_cancelAnimationFrame(${animation_frame});
if (!${this.var}.paused) ${animation_frame} = @raf(${handler});`}
${needs_lock && `${lock} = true;`}
ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''});
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/compile/render-dom/wrappers/Head.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ export default class HeadWrapper extends Wrapper {
}

render(block: Block, _parent_node: string, _parent_nodes: string) {
this.fragment.render(block, 'document.head', 'nodes');
this.fragment.render(block, '@_document.head', 'nodes');
}
}
2 changes: 1 addition & 1 deletion src/compiler/compile/render-dom/wrappers/IfBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export default class IfBlockWrapper extends Wrapper {

const vars = { name, anchor, if_name, has_else, has_transitions };

const detaching = (parent_node && parent_node !== 'document.head') ? '' : 'detaching';
const detaching = (parent_node && parent_node !== '@_document.head') ? '' : 'detaching';

if (this.node.else) {
if (has_outros) {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/compile/render-dom/wrappers/RawMustacheTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default class RawMustacheTagWrapper extends Tag {
render(block: Block, parent_node: string, parent_nodes: string) {
const name = this.var;

const in_head = parent_node === 'document.head';
const in_head = parent_node === '@_document.head';
const needs_anchors = !parent_node || in_head;

// if in head always needs anchors
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/compile/render-dom/wrappers/Title.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ export default class TitleWrapper extends Wrapper {
const init = this.node.should_cache ? `${last} = ${value}` : value;

block.builders.init.add_line(
`document.title = ${init};`
`@_document.title = ${init};`
);
const updater = `document.title = ${this.node.should_cache ? last : value};`;
const updater = `@_document.title = ${this.node.should_cache ? last : value};`;

if (all_dependencies.size) {
const dependencies = Array.from(all_dependencies);
Expand All @@ -95,7 +95,7 @@ export default class TitleWrapper extends Wrapper {
? stringify((this.node.children[0] as Text).data)
: '""';

block.builders.hydrate.add_line(`document.title = ${value};`);
block.builders.hydrate.add_line(`@_document.title = ${value};`);
}
}
}
Loading