Skip to content

Commit

Permalink
HTML bundle loader (#1732)
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett authored Jul 16, 2018
1 parent 29e13ab commit b3d2975
Show file tree
Hide file tree
Showing 16 changed files with 211 additions and 9 deletions.
25 changes: 17 additions & 8 deletions packages/core/parcel/src/Bundler.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ class Bundler extends EventEmitter {
browser: require.resolve('./builtins/loaders/browser/js-loader'),
node: require.resolve('./builtins/loaders/node/js-loader')
});
this.addBundleLoader('html', {
browser: require.resolve('./builtins/loaders/browser/html-loader'),
node: require.resolve('./builtins/loaders/node/html-loader')
});

this.pending = false;
this.loadedAssets = new Map();
Expand Down Expand Up @@ -620,6 +624,12 @@ class Bundler extends EventEmitter {
let isEntryAsset =
asset.parentBundle && asset.parentBundle.entryAsset === asset;

// If the asset generated a representation for the parent bundle type, and this
// is not an async import, add it to the current bundle
if (bundle.type && asset.generated[bundle.type] != null && !dep.dynamic) {
bundle.addAsset(asset);
}

if ((dep && dep.dynamic) || !bundle.type) {
// If the asset is already the entry asset of a bundle, don't create a duplicate.
if (isEntryAsset) {
Expand All @@ -628,24 +638,23 @@ class Bundler extends EventEmitter {

// Create a new bundle for dynamic imports
bundle = bundle.createChildBundle(asset, dep);
} else if (asset.type && !this.packagers.has(asset.type)) {
} else if (
asset.type &&
!this.packagers.get(asset.type).shouldAddAsset(bundle, asset)
) {
// If the asset is already the entry asset of a bundle, don't create a duplicate.
if (isEntryAsset) {
return;
}

// No packager is available for this asset type. Create a new bundle with only this asset.
bundle.createSiblingBundle(asset);
// No packager is available for this asset type, or the packager doesn't support
// combining this asset into the bundle. Create a new bundle with only this asset.
bundle = bundle.createSiblingBundle(asset, dep);
} else {
// Add the asset to the common bundle of the asset's type
bundle.getSiblingBundle(asset.type).addAsset(asset);
}

// If the asset generated a representation for the parent bundle type, also add it there
if (asset.generated[bundle.type] != null) {
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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = function loadHTMLBundle(bundle) {
return fetch(bundle).then(function (res) {
return res.text();
});
};
17 changes: 17 additions & 0 deletions packages/core/parcel/src/builtins/loaders/node/html-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
var fs = require('fs');

module.exports = function loadHTMLBundle(bundle) {
return new Promise(function(resolve, reject) {
fs.readFile(__dirname + bundle, 'utf8', function(err, data) {
if (err) {
reject(err);
} else {
// wait for the next event loop iteration, so we are sure
// the current module is fully loaded
setImmediate(function() {
resolve(data);
});
}
});
});
};
5 changes: 5 additions & 0 deletions packages/core/parcel/src/packagers/HTMLPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ const metadataContent = new Set([
]);

class HTMLPackager extends Packager {
static shouldAddAsset() {
// We cannot combine multiple HTML files together - they should be written as separate bundles.
return false;
}

async addAsset(asset) {
let html = asset.generated.html || '';

Expand Down
4 changes: 4 additions & 0 deletions packages/core/parcel/src/packagers/Packager.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ class Packager {
this.options = bundler.options;
}

static shouldAddAsset() {
return true;
}

async setup() {
// Create sub-directories if needed
if (this.bundle.name.includes(path.sep)) {
Expand Down
5 changes: 5 additions & 0 deletions packages/core/parcel/src/packagers/RawPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ const path = require('path');
const fs = require('../utils/fs');

class RawPackager extends Packager {
static shouldAddAsset() {
// We cannot combine multiple raw assets together - they should be written as separate bundles.
return false;
}

// Override so we don't create a file for this bundle.
// Each asset will be emitted as a separate file instead.
setup() {}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background: red;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = import('./other.html');
10 changes: 10 additions & 0 deletions packages/core/parcel/test/integration/import-html-async/other.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<h1>Other page</h1>
<img src="100x100.png" />
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background: red;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
output(require('./other.html'));
10 changes: 10 additions & 0 deletions packages/core/parcel/test/integration/import-html-sync/other.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<h1>Other page</h1>
<img src="100x100.png" />
</body>
</html>
126 changes: 125 additions & 1 deletion packages/core/parcel/test/javascript.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const assert = require('assert');
const fs = require('../src/utils/fs');
const path = require('path');
const {bundle, run, assertBundleTree} = require('./utils');
const {bundle, run, assertBundleTree, deferred} = require('./utils');
const {mkdirp} = require('../src/utils/fs');

describe('javascript', function() {
Expand Down Expand Up @@ -1222,4 +1222,128 @@ describe('javascript', function() {
let module = await run(b);
assert.equal(module.default, 'Hello Hello!');
});

it('should support importing HTML from JS async', async function() {
let b = await bundle(
__dirname + '/integration/import-html-async/index.js',
{sourceMaps: false}
);

await assertBundleTree(b, {
name: 'index.js',
assets: [
'index.js',
'bundle-loader.js',
'bundle-url.js',
'html-loader.js'
],
childBundles: [
{
type: 'html',
assets: ['other.html'],
childBundles: [
{
type: 'png',
assets: ['100x100.png'],
childBundles: []
},
{
type: 'css',
assets: ['index.css'],
childBundles: []
}
]
}
]
});

let output = await run(b);
assert.equal(typeof output, 'string');
assert(output.includes('<html>'));
assert(output.includes('Other page'));
});

it('should support importing HTML from JS async with --target=node', async function() {
let b = await bundle(
__dirname + '/integration/import-html-async/index.js',
{
target: 'node',
sourceMaps: false
}
);

await assertBundleTree(b, {
name: 'index.js',
assets: [
'index.js',
'bundle-loader.js',
'bundle-url.js',
'html-loader.js'
],
childBundles: [
{
type: 'html',
assets: ['other.html'],
childBundles: [
{
type: 'png',
assets: ['100x100.png'],
childBundles: []
},
{
type: 'css',
assets: ['index.css'],
childBundles: []
}
]
}
]
});

let output = await run(b);
assert.equal(typeof output, 'string');
assert(output.includes('<html>'));
assert(output.includes('Other page'));
});

it('should support importing HTML from JS sync', async function() {
let b = await bundle(__dirname + '/integration/import-html-sync/index.js', {
sourceMaps: false
});

await assertBundleTree(b, {
name: 'index.js',
assets: [
'index.js',
'bundle-loader.js',
'bundle-url.js',
'html-loader.js'
],
childBundles: [
{
type: 'html',
assets: ['other.html'],
childBundles: [
{
type: 'png',
assets: ['100x100.png'],
childBundles: []
},
{
type: 'css',
assets: ['index.css'],
childBundles: []
}
]
}
]
});

let promise = deferred();
await run(b, {output: promise.resolve}, {require: false});
let output = await promise;
assert.equal(typeof output, 'string');
assert(output.includes('<html>'));
assert(output.includes('Other page'));
});
});
5 changes: 5 additions & 0 deletions packages/core/parcel/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ function prepareBrowserContext(bundle, globals) {
nodeFS.readFileSync(path.join(__dirname, 'dist', url))
).buffer
);
},
text() {
return Promise.resolve(
nodeFS.readFileSync(path.join(__dirname, 'dist', url), 'utf8')
);
}
});
}
Expand Down

0 comments on commit b3d2975

Please sign in to comment.