From fb3f9d7a5e120766dd3656ce00b4bb07e76d6af1 Mon Sep 17 00:00:00 2001 From: Jasper De Moor Date: Sat, 6 Jan 2018 16:57:50 +0100 Subject: [PATCH] CSS Hotreload if put in html (#128) * css refresh on html * clean and clear up code a lil * remove console log * improve code structure * Ensure that CSS HMR JS is actually included in the bundle * Refactor sibling bundle insertion in HTMLPackager and add test * Use urlJoin --- src/Bundler.js | 9 +++++ src/packagers/HTMLPackager.js | 52 ++++++++++++++++--------- test/html.js | 27 +++++++++++++ test/integration/html-css-js/index.css | 3 ++ test/integration/html-css-js/index.html | 10 +++++ 5 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 test/integration/html-css-js/index.css create mode 100644 test/integration/html-css-js/index.html diff --git a/src/Bundler.js b/src/Bundler.js index 7260a21f17b..b6126a127c4 100644 --- a/src/Bundler.js +++ b/src/Bundler.js @@ -410,6 +410,15 @@ class Bundler extends EventEmitter { bundle.addAsset(asset); } + // Add the asset to sibling bundles for each generated type + if (asset.type && asset.generated[asset.type]) { + for (let t in asset.generated) { + if (asset.generated[t]) { + bundle.getSiblingBundle(t).addAsset(asset); + } + } + } + asset.parentBundle = bundle; for (let dep of asset.dependencies.values()) { diff --git a/src/packagers/HTMLPackager.js b/src/packagers/HTMLPackager.js index 6bef663e485..2a6fb069adc 100644 --- a/src/packagers/HTMLPackager.js +++ b/src/packagers/HTMLPackager.js @@ -7,23 +7,22 @@ class HTMLPackager extends Packager { async addAsset(asset) { let html = asset.generated.html || ''; - // Find child bundles (e.g. JS) that have a sibling CSS bundle, + // Find child bundles that have JS or CSS sibling bundles, // add them to the head so they are loaded immediately. - let cssBundles = Array.from(this.bundle.childBundles) - .map(b => b.siblingBundles.get('css')) - .filter(Boolean); - - if (cssBundles.length > 0) { - html = posthtml(this.insertCSSBundles.bind(this, cssBundles)).process( - html, - {sync: true} - ).html; + let siblingBundles = Array.from(this.bundle.childBundles) + .reduce((p, b) => p.concat([...b.siblingBundles.values()]), []) + .filter(b => b.type === 'css' || b.type === 'js'); + + if (siblingBundles.length > 0) { + html = posthtml( + this.insertSiblingBundles.bind(this, siblingBundles) + ).process(html, {sync: true}).html; } await this.dest.write(html); } - insertCSSBundles(cssBundles, tree) { + getHeadContent(tree) { let head = find(tree, 'head'); if (!head) { let html = find(tree, 'html'); @@ -35,14 +34,29 @@ class HTMLPackager extends Packager { head.content = []; } - for (let bundle of cssBundles) { - head.content.push({ - tag: 'link', - attrs: { - rel: 'stylesheet', - href: urlJoin(this.options.publicURL, path.basename(bundle.name)) - } - }); + return head; + } + + insertSiblingBundles(siblingBundles, tree) { + let head = this.getHeadContent(tree); + + for (let bundle of siblingBundles) { + if (bundle.type === 'css') { + head.content.push({ + tag: 'link', + attrs: { + rel: 'stylesheet', + href: urlJoin(this.options.publicURL, path.basename(bundle.name)) + } + }); + } else if (bundle.type === 'js') { + head.content.push({ + tag: 'script', + attrs: { + src: urlJoin(this.options.publicURL, path.basename(bundle.name)) + } + }); + } } } } diff --git a/test/html.js b/test/html.js index 436fffe0bac..4a322479f7a 100644 --- a/test/html.js +++ b/test/html.js @@ -151,6 +151,33 @@ describe('html', function() { ); }); + it('should insert sibling JS bundles for CSS files in the HEAD', async function() { + let b = await bundle(__dirname + '/integration/html-css-js/index.html', { + hmr: true + }); + + assertBundleTree(b, { + name: 'index.html', + assets: ['index.html'], + childBundles: [ + { + type: 'css', + assets: ['index.css'], + childBundles: [ + { + type: 'js', + assets: ['index.css', 'bundle-url.js', 'css-loader.js'], + childBundles: [] + } + ] + } + ] + }); + + let html = fs.readFileSync(__dirname + '/dist/index.html'); + assert(/