feat: simplify HMR implementation (#11132)

* chore: simplify HMR implementation

* changeset

* unused

* prettier
pull/11134/head
Rich Harris 1 year ago committed by GitHub
parent a740b7bb43
commit d5776c3ec3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
feat: simplify HMR implementation

@ -422,32 +422,31 @@ export function client_component(source, analysis, options) {
)
];
// In order for hmr to work correctly, we need associate each component with a unique key.
// This is because bundlers might put many components into a the same module (usuaully as a chunk).
// `import.meta.hot` will then be the same object for all components in that modules.
if (options.hmr && options.filename) {
if (options.hmr) {
body.push(
b.export_default(
b.conditional(
b.import_meta_hot(),
b.call(
'$.hmr',
b.member(b.import_meta_hot(), b.id('data')),
b.id(analysis.name),
b.literal(options.filename)
),
b.id(analysis.name)
)
),
b.if(
b.import_meta_hot(),
b.stmt(b.call('import.meta.hot.acceptExports', b.literal('default')))
b.id('import.meta.hot'),
b.block([
b.const(b.id('s'), b.call('$.source', b.id(analysis.name))),
b.stmt(b.assignment('=', b.id(analysis.name), b.call('$.hmr', b.id('s')))),
b.stmt(
b.call(
'import.meta.hot.accept',
b.arrow(
[b.id('module')],
b.block([
b.stmt(b.call('$.set', b.id('s'), b.member(b.id('module'), b.id('default'))))
])
)
)
)
])
)
);
} else {
body.push(b.export_default(b.id(analysis.name)));
}
body.push(b.export_default(b.id(analysis.name)));
if (options.dev) {
if (options.filename) {
let filename = options.filename;

@ -600,20 +600,6 @@ export function throw_error(str) {
};
}
/**
* @return {import('estree').MemberExpression}
*/
export function import_meta_hot() {
return member(
{
type: 'MetaProperty',
meta: id('import'),
property: id('meta')
},
id('hot')
);
}
export {
await_builder as await,
let_builder as let,

@ -1,55 +1,38 @@
import { block, branch, destroy_effect } from '../reactivity/effects.js';
import { set, source } from '../reactivity/sources.js';
import { set_should_intro } from '../render.js';
import { get } from '../runtime.js';
/**
* @template {(anchor: Comment, props: any) => any} Component
* @param {{ components: Map<string, { source: import("#client").Source<Component>; wrapper: null | Component; }> }} hot_data
* @param {string} key
* @param {Component} component
* @param {import("#client").Source<Component>} source
*/
export function hmr(hot_data, component, key) {
var components = (hot_data.components ??= new Map());
var data = components.get(key);
if (data === undefined) {
components.set(
key,
(data = {
source: source(component),
wrapper: null
})
);
} else {
set(data.source, component);
}
const component_source = data.source;
return (data.wrapper ??= /** @type {Component} */ (
(anchor, props) => {
let instance = {};
/** @type {import("#client").Effect} */
let effect;
block(() => {
const component = get(component_source);
if (effect) {
// @ts-ignore
for (var k in instance) delete instance[k];
destroy_effect(effect);
}
effect = branch(() => {
set_should_intro(false);
Object.assign(instance, component(anchor, props));
set_should_intro(true);
});
export function hmr(source) {
/**
* @param {Comment} anchor
* @param {any} props
*/
return (anchor, props) => {
let instance = {};
/** @type {import("#client").Effect} */
let effect;
block(() => {
const component = get(source);
if (effect) {
// @ts-ignore
for (var k in instance) delete instance[k];
destroy_effect(effect);
}
effect = branch(() => {
set_should_intro(false);
Object.assign(instance, component(anchor, props));
set_should_intro(true);
});
});
return instance;
}
));
return instance;
};
}

@ -0,0 +1,7 @@
import { test } from '../../test';
export default test({
compileOptions: {
hmr: true
}
});

@ -0,0 +1,28 @@
// index.svelte (Svelte VERSION)
// Note: compiler output will change before 5.0 is released!
import "svelte/internal/disclose-version";
import * as $ from "svelte/internal/client";
var root = $.template(`<h1>hello world</h1>`);
function Hmr($$anchor, $$props) {
$.push($$props, false);
$.init();
var h1 = root();
$.append($$anchor, h1);
$.pop();
}
if (import.meta.hot) {
const s = $.source(Hmr);
Hmr = $.hmr(s);
import.meta.hot.accept((module) => {
$.set(s, module.default);
});
}
export default Hmr;

@ -0,0 +1,9 @@
// index.svelte (Svelte VERSION)
// Note: compiler output will change before 5.0 is released!
import * as $ from "svelte/internal/server";
export default function Hmr($$payload, $$props) {
$.push(false);
$$payload.out += `<h1>hello world</h1>`;
$.pop();
}
Loading…
Cancel
Save