diff --git a/src/compile/Component.ts b/src/compile/Component.ts index a934c426c6..065500dbe1 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -201,10 +201,13 @@ export default class Component { return sigil.slice(1) + name; }); - const importedHelpers = Array.from(helpers).concat('SvelteComponent').sort().map(name => { - const alias = this.alias(name); - return { name, alias }; - }); + const importedHelpers = Array.from(helpers) + .concat(options.dev ? '$$ComponentDev' : '$$Component') + .sort() + .map(name => { + const alias = this.alias(name); + return { name, alias }; + }); const sharedPath = options.shared || 'svelte/internal.js'; diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index 3d303bf306..e9416c6c8e 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -110,8 +110,16 @@ export default function dom( component.event_handlers.map(handler => handler.name) ); + const superclass = component.alias(options.dev ? '$$ComponentDev' : '$$Component'); + + if (options.dev && !options.hydratable) { + block.builders.hydrate.addLine( + 'throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");' + ); + } + builder.addBlock(deindent` - class ${name} extends @SvelteComponent { + class ${name} extends ${superclass} { $$init($$make_dirty) { ${component.javascript || component.exports.map(x => `let ${x.name};`)} diff --git a/src/internal/SvelteComponent.js b/src/internal/Component.js similarity index 91% rename from src/internal/SvelteComponent.js rename to src/internal/Component.js index 4adebf0920..84924d57b6 100644 --- a/src/internal/SvelteComponent.js +++ b/src/internal/Component.js @@ -3,7 +3,7 @@ import { set_current_component } from './lifecycle.js' import { run_all } from './utils.js'; import { blankObject } from './utils.js'; -export class SvelteComponent { +export class $$Component { constructor(options) { this.$$onprops = []; this.$$onmount = []; @@ -105,4 +105,14 @@ export class SvelteComponent { run_all(this.$$onupdate); this.$$dirty = null; } +} + +export class $$ComponentDev extends $$Component { + constructor(options) { + if (!options || !options.target) { + throw new Error(`'target' is a required option`); + } + + super(options); + } } \ No newline at end of file diff --git a/src/internal/index.js b/src/internal/index.js index 307dccc074..6b134b677d 100644 --- a/src/internal/index.js +++ b/src/internal/index.js @@ -8,4 +8,4 @@ export * from './spread.js'; export * from './ssr.js'; export * from './transitions.js'; export * from './utils.js'; -export * from './SvelteComponent.js'; \ No newline at end of file +export * from './Component.js'; \ No newline at end of file diff --git a/test/runtime/index.js b/test/runtime/index.js index 29ea434e92..ede6e5d478 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -3,6 +3,8 @@ import chalk from 'chalk'; import * as path from "path"; import * as fs from "fs"; import * as acorn from "acorn"; +import { rollup } from 'rollup'; +import virtual from 'rollup-plugin-virtual'; import { transitionManager } from "../../internal.js"; import { @@ -213,35 +215,52 @@ describe.only("runtime", () => { runTest(dir, internal, true); }); - it("fails if options.target is missing in dev mode", () => { - const { js } = svelte$.compile(`
`, { - format: "iife", + async function create_component(src = '') { + const { js } = svelte$.compile(src, { + format: "es", // TODO change this to esm name: "SvelteComponent", dev: true }); - const SvelteComponent = eval( - `(function () { ${js.code}; return SvelteComponent; }())` + const bundle = await rollup({ + input: 'main.js', + plugins: [ + virtual({ + 'main.js': js.code + }), + { + resolveId: (importee, importer) => { + if (importee.startsWith('svelte/')) { + return importee.replace('svelte', process.cwd()); + } + } + } + ] + }); + + const result = await bundle.generate({ + format: 'iife', + name: 'App' + }); + + return eval( + `(function () { ${result.code}; return App; }())` ); + } + + it("fails if options.target is missing in dev mode", async () => { + const App = await create_component(); assert.throws(() => { - new SvelteComponent(); + new App(); }, /'target' is a required option/); }); - it("fails if options.hydrate is true but the component is non-hydratable", () => { - const { js } = svelte$.compile(``, { - format: "iife", - name: "SvelteComponent", - dev: true - }); - - const SvelteComponent = eval( - `(function () { ${js.code}; return SvelteComponent; }())` - ); + it("fails if options.hydrate is true but the component is non-hydratable", async () => { + const App = await create_component(); assert.throws(() => { - new SvelteComponent({ + new App({ target: {}, hydrate: true });