Skip to content

Commit

Permalink
feature enhanced hmr (#827)
Browse files Browse the repository at this point in the history
* enhanced hmr

* Update dev.ts

Co-authored-by: Fred K. Schott <[email protected]>
  • Loading branch information
Akimyou and FredKSchott authored Aug 22, 2020
1 parent 170890f commit c5490fd
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 27 deletions.
59 changes: 33 additions & 26 deletions packages/snowpack/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,29 +500,6 @@ export async function command(commandOptions: CommandOptions) {
code =
`import './${path.basename(reqPath).replace(/.js$/, '.css.proxy.js')}';\n` + code;

if (reqUrlHmrParam)
code = await transformEsmImports(code as string, (imp) => {
const importUrl = path.posix.resolve(path.posix.dirname(reqPath), imp);
const node = hmrEngine.getEntry(importUrl);
if (node && node.needsReplacement) {
hmrEngine.markEntryForReplacement(node, false);
return `${imp}?${reqUrlHmrParam}`;
}
return imp;
});

// hmr
const isHmrEnabled = code.includes('import.meta.hot');
const rawImports = await scanCodeImportsExports(code);
const resolvedImports = rawImports.map((imp) => {
let spec = code.substring(imp.s, imp.e);
if (imp.d > -1) {
spec = matchImportSpecifier(spec) || '';
}
return path.posix.resolve(path.posix.dirname(reqPath), spec);
});
hmrEngine.setEntry(originalReqPath, resolvedImports, isHmrEnabled);

// source mapping
if (sourceMap) code = jsSourceMappingURL(code, sourceMappingURL);

Expand Down Expand Up @@ -573,6 +550,34 @@ If Snowpack is having trouble detecting the import, add ${colors.bold(
return spec;
},
);

let code = wrappedResponse;
if (responseFileExt === '.js' && reqUrlHmrParam)
code = await transformEsmImports(code as string, (imp) => {
const importUrl = path.posix.resolve(path.posix.dirname(reqPath), imp);
const node = hmrEngine.getEntry(importUrl);
if (node && node.needsReplacement) {
hmrEngine.markEntryForReplacement(node, false);
return `${imp}?${reqUrlHmrParam}`;
}
return imp;
});

if (responseFileExt === '.js') {
const isHmrEnabled = code.includes('import.meta.hot');
const rawImports = await scanCodeImportsExports(code);
const resolvedImports = rawImports.map((imp) => {
let spec = code.substring(imp.s, imp.e);
if (imp.d > -1) {
spec = matchImportSpecifier(spec) || '';
}
spec = spec.replace(/\?mtime=[0-9]+$/, '');
return path.posix.resolve(path.posix.dirname(reqPath), spec);
});
hmrEngine.setEntry(originalReqPath, resolvedImports, isHmrEnabled);
}

wrappedResponse = code;
return wrappedResponse;
}

Expand Down Expand Up @@ -770,8 +775,10 @@ ${err}`);
if (node && node.isHmrAccepted) {
// Found a boundary, no bubbling needed
} else if (node && node.dependents.size > 0) {
hmrEngine.markEntryForReplacement(node, true);
node.dependents.forEach((dep) => updateOrBubble(dep, visited));
node.dependents.forEach((dep) => {
hmrEngine.markEntryForReplacement(node, true);
updateOrBubble(dep, visited);
});
} else {
// We've reached the top, trigger a full page refresh
hmrEngine.broadcastMessage({type: 'reload'});
Expand All @@ -787,7 +794,7 @@ ${err}`);
}

// Append ".proxy.js" to Non-JS files to match their registered URL in the client app.
if (!updateUrl.endsWith('.js') && !updateUrl.endsWith('.module.css')) {
if (!updateUrl.endsWith('.js')) {
updateUrl += '.proxy.js';
}
// Check if a virtual file exists in the resource cache (ex: CSS from a Svelte file)
Expand Down
9 changes: 8 additions & 1 deletion packages/snowpack/src/hmr-server-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface Dependency {
isHmrEnabled: boolean;
isHmrAccepted: boolean;
needsReplacement: boolean;
needsReplacementCount: number;
}

export class EsmHmrEngine {
Expand Down Expand Up @@ -51,6 +52,7 @@ export class EsmHmrEngine {
dependencies: new Set(),
dependents: new Set(),
needsReplacement: false,
needsReplacementCount: 0,
isHmrEnabled: false,
isHmrAccepted: false,
};
Expand Down Expand Up @@ -99,7 +101,12 @@ export class EsmHmrEngine {
}

markEntryForReplacement(entry: Dependency, state: boolean) {
entry.needsReplacement = state;
if (state) {
entry.needsReplacementCount++;
} else {
entry.needsReplacementCount--;
}
entry.needsReplacement = !!entry.needsReplacementCount;
}

broadcastMessage(data: object) {
Expand Down

1 comment on commit c5490fd

@vercel
Copy link

@vercel vercel bot commented on c5490fd Aug 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.