Skip to content

Commit

Permalink
add support for live updating a CSS file directly (not only imported …
Browse files Browse the repository at this point in the history
…via JS)
  • Loading branch information
FredKSchott committed Nov 26, 2020
1 parent c34c9cf commit d7b528c
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
34 changes: 30 additions & 4 deletions snowpack/assets/hmr-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ function sendSocketMessage(msg) {
}
let socketURL = typeof window !== 'undefined' && window.HMR_WEBSOCKET_URL;
if (!socketURL) {
const socketHost = typeof window !== 'undefined' && window.HMR_WEBSOCKET_PORT ?
`${location.hostname}:${window.HMR_WEBSOCKET_PORT}` : location.host
const socketHost =
typeof window !== 'undefined' && window.HMR_WEBSOCKET_PORT
? `${location.hostname}:${window.HMR_WEBSOCKET_PORT}`
: location.host;
socketURL = (location.protocol === 'http:' ? 'ws://' : 'wss://') + socketHost + '/';
}

Expand Down Expand Up @@ -112,8 +114,32 @@ export function createHotContext(fullUrl) {
return state;
}

/** Called when any CSS file is loaded. */
async function runCssStyleAccept({url: id}) {
const nonce = Date.now();
const oldLinkEl =
document.head.querySelector(`link[data-hmr="${id}"]`) ||
document.head.querySelector(`link[href="${id}"]`);
if (!oldLinkEl) {
return true;
}
const linkEl = oldLinkEl.cloneNode(false);
linkEl.dataset.hmr = id;
linkEl.type = 'text/css';
linkEl.rel = 'stylesheet';
linkEl.href = id + '?mtime=' + nonce;
linkEl.addEventListener(
'load',
// Once loaded, remove the old link element (with some delay, to avoid FOUC)
() => setTimeout(() => document.head.removeChild(oldLinkEl), 30),
false,
);
oldLinkEl.parentNode.insertBefore(linkEl, oldLinkEl)
return true;
}

/** Called when a new module is loaded, to pass the updated module to the "active" module */
async function runModuleAccept({url: id, bubbled}) {
async function runJsModuleAccept({url: id, bubbled}) {
const state = REGISTERED_MODULES[id];
if (!state) {
return false;
Expand Down Expand Up @@ -168,7 +194,7 @@ socket.addEventListener('message', ({data: _data}) => {
}
if (data.type === 'update') {
log('message: update', data);
runModuleAccept(data)
(data.url.endsWith('.css') ? runCssStyleAccept(data) : runJsModuleAccept(data))
.then((ok) => {
if (ok) {
clearErrorOverlay();
Expand Down
1 change: 0 additions & 1 deletion snowpack/src/build/build-import-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ if (typeof document !== 'undefined') {${
const styleEl = document.createElement("style");
const codeEl = document.createTextNode(code);
styleEl.type = 'text/css';
styleEl.appendChild(codeEl);
document.head.appendChild(styleEl);
}`;
Expand Down
11 changes: 10 additions & 1 deletion snowpack/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1261,16 +1261,24 @@ export async function startDevServer(commandOptions: CommandOptions): Promise<Sn
hmrEngine.broadcastMessage({type: 'reload'});
}
}
function handleHmrUpdate(fileLoc: string, updatedUrl: string) {
function handleHmrUpdate(fileLoc: string, originalUrl: string) {
if (isLiveReloadPaused) {
return;
}

// CSS files may be loaded directly in the client (not via JS import / .proxy.js)
// so send an "update" event to live update if thats the case.
if (originalUrl.endsWith('.css') && !originalUrl.endsWith('.module.css')) {
hmrEngine.broadcastMessage({type: 'update', url: originalUrl, bubbled: false});
}

// Append ".proxy.js" to Non-JS files to match their registered URL in the
// client app.
let updatedUrl = originalUrl;
if (!updatedUrl.endsWith('.js')) {
updatedUrl += '.proxy.js';
}

// Check if a virtual file exists in the resource cache (ex: CSS from a
// Svelte file) If it does, mark it for HMR replacement but DONT trigger a
// separate HMR update event. This is because a virtual resource doesn't
Expand All @@ -1281,6 +1289,7 @@ export async function startDevServer(commandOptions: CommandOptions): Promise<Sn
if (virtualNode) {
hmrEngine.markEntryForReplacement(virtualNode, true);
}

// If the changed file exists on the page, trigger a new HMR update.
if (hmrEngine.getEntry(updatedUrl)) {
updateOrBubble(updatedUrl, new Set());
Expand Down

0 comments on commit d7b528c

Please sign in to comment.