Skip to content

Commit

Permalink
Include prelude for shared bundles between main script and workers (p…
Browse files Browse the repository at this point in the history
  • Loading branch information
mischnic authored Feb 14, 2021
1 parent ac921d9 commit f975010
Show file tree
Hide file tree
Showing 24 changed files with 316 additions and 169 deletions.
9 changes: 9 additions & 0 deletions packages/core/core/src/BundleGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -1442,4 +1442,13 @@ export default class BundleGraph {
this._graph.addEdge(edge.from, edge.to, edge.type);
}
}

isEntryBundleGroup(bundleGroup: BundleGroup): boolean {
return this._graph
.getNodesConnectedTo(
nullthrows(this._graph.getNode(getBundleGroupId(bundleGroup))),
'bundle',
)
.some(n => n.type === 'root');
}
}
4 changes: 4 additions & 0 deletions packages/core/core/src/public/BundleGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ export default class BundleGraph<TBundle: IBundle>
);
}

isEntryBundleGroup(bundleGroup: BundleGroup): boolean {
return this.#graph.isEntryBundleGroup(bundleGroup);
}

getChildBundles(bundle: IBundle): Array<TBundle> {
return this.#graph
.getChildBundles(bundleToInternalBundle(bundle))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script src="./index.js"></script>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
new Worker("./main-worker");
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
new Worker("./main-worker");
import {add} from "lodash";

output = add(1, 2);

new Worker("./worker");
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {add} from "lodash";

output = add(10, 20);
Empty file.
50 changes: 49 additions & 1 deletion packages/core/integration-tests/test/output-formats.js
Original file line number Diff line number Diff line change
Expand Up @@ -1380,11 +1380,59 @@ describe('output formats', function() {
});

describe('global', function() {
it('should support split bundles between main script and workers', async function() {
let b = await bundle(
path.join(
__dirname,
'/integration/formats/global-split-worker/index.html',
),
{
mode: 'production',
defaultTargetOptions: {
shouldOptimize: false,
},
},
);

assertBundles(b, [
{
type: 'js',
assets: [
'bundle-manifest.js',
'bundle-url.js',
'get-worker-url.js',
'index.js',
'JSRuntime.js',
'JSRuntime.js',
'relative-path.js',
],
},
{type: 'html', assets: ['index.html']},
{type: 'js', assets: ['lodash.js']},
{type: 'js', assets: ['worker.js']},
]);

let workerBundle;
assert.strictEqual(
await run(b, {
Worker: class {
constructor(url) {
workerBundle = nullthrows(
b.getBundles().find(b => b.name === path.posix.basename(url)),
);
}
},
}),
3,
);
assert.strictEqual(await runBundle(b, workerBundle), 30);
});

it('should support async split bundles for workers', async function() {
await bundle(
path.join(
__dirname,
'/integration/formats/global-split-worker/index.html',
'/integration/formats/global-split-worker-async/index.html',
),
{
mode: 'production',
Expand Down
74 changes: 72 additions & 2 deletions packages/core/test-utils/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ export async function runBundles(
promises = browser.promises;
break;
}
case 'web-worker': {
let prepared = prepareWorkerContext(parent.filePath, globals);
ctx = prepared.ctx;
promises = prepared.promises;
break;
}
default:
throw new Error('Unknown target ' + target);
}
Expand Down Expand Up @@ -533,7 +539,7 @@ function prepareBrowserContext(
// '"use strict";\n' +
overlayFS.readFileSync(file, 'utf8'),
{
filename: file,
filename: path.basename(file),
},
).runInContext(ctx);

Expand Down Expand Up @@ -620,6 +626,70 @@ function prepareBrowserContext(
return {ctx, promises};
}

function prepareWorkerContext(
filePath: FilePath,
globals: mixed,
): {|
ctx: vm$Context,
promises: Array<Promise<mixed>>,
|} {
let promises = [];

var exports = {};
var ctx = Object.assign(
{
exports,
module: {exports},
WebSocket,
console,
location: {hostname: 'localhost', origin: 'http://localhost'},
importScripts(...urls) {
for (let u of urls) {
new vm.Script(
overlayFS.readFileSync(
path.join(path.dirname(filePath), url.parse(u).pathname),
'utf8',
),
{
filename: path.basename(url.parse(u).pathname),
},
).runInContext(ctx);
}
},
fetch(url) {
return Promise.resolve({
async arrayBuffer() {
let readFilePromise = overlayFS.readFile(
path.join(path.dirname(filePath), url),
);
promises.push(readFilePromise);
return new Uint8Array(await readFilePromise).buffer;
},
text() {
let readFilePromise = overlayFS.readFile(
path.join(path.dirname(filePath), url),
'utf8',
);
promises.push(readFilePromise);
return readFilePromise;
},
});
},
atob(str) {
return Buffer.from(str, 'base64').toString('binary');
},
btoa(str) {
return Buffer.from(str, 'binary').toString('base64');
},
URL,
},
globals,
);

ctx.window = ctx.self = ctx;
return {ctx, promises};
}

const nodeCache = {};
// no filepath = ESM
function prepareNodeContext(filePath, globals) {
Expand Down Expand Up @@ -683,7 +753,7 @@ function prepareNodeContext(filePath, globals) {
//'"use strict";\n' +
overlayFS.readFileSync(res, 'utf8'),
{
filename: res,
filename: path.basename(res),
},
).runInContext(ctx);
return ctx.module.exports;
Expand Down
1 change: 1 addition & 0 deletions packages/core/types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,7 @@ export interface BundleGraph<TBundle: Bundle> {
getIncomingDependencies(asset: Asset): Array<Dependency>;
/** Get the asset that created the dependency. */
getAssetWithDependency(dep: Dependency): ?Asset;
isEntryBundleGroup(bundleGroup: BundleGroup): boolean;
/**
* Returns undefined if the specified dependency was excluded or wasn't async \
* and otherwise the BundleGroup or Asset that the dependency resolves to.
Expand Down
6 changes: 1 addition & 5 deletions packages/packagers/js/src/JSPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,14 @@ export default (new Packager({
// If scope hoisting is enabled, we use a different code path.
if (bundle.env.shouldScopeHoist) {
let wrappedAssets = new Set<string>();
let {ast, referencedAssets} = link({
let ast = link({
bundle,
bundleGraph,
ast: await concat({
bundle,
bundleGraph,
options,
wrappedAssets,
parcelRequireName,
}),
options,
wrappedAssets,
Expand All @@ -87,11 +86,8 @@ export default (new Packager({
traverse.cache.clear();

let {contents, map} = generate({
bundleGraph,
bundle,
ast,
referencedAssets,
parcelRequireName,
options,
});
return replaceReferences({
Expand Down
18 changes: 0 additions & 18 deletions packages/shared/scope-hoisting/src/concat.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import type {
VariableDeclaration,
} from '@babel/types';

import path from 'path';
import * as t from '@babel/types';
import {
isArrayPattern,
Expand All @@ -38,24 +37,16 @@ import {
} from '@parcel/babylon-walk';
import {PromiseQueue, relativeUrl, relativePath} from '@parcel/utils';
import invariant from 'assert';
import fs from 'fs';
import nullthrows from 'nullthrows';
import template from '@babel/template';
import {
assertString,
getName,
getIdentifier,
parse,
needsPrelude,
needsDefaultInterop,
} from './utils';

const PRELUDE_PATH = path.join(__dirname, 'prelude.js');
const PRELUDE = parse(
fs.readFileSync(path.join(__dirname, 'prelude.js'), 'utf8'),
PRELUDE_PATH,
);

const DEFAULT_INTEROP_TEMPLATE = template.statement<
{|
NAME: LVal,
Expand Down Expand Up @@ -83,13 +74,11 @@ export async function concat({
bundleGraph,
options,
wrappedAssets,
parcelRequireName,
}: {|
bundle: NamedBundle,
bundleGraph: BundleGraph<NamedBundle>,
options: PluginOptions,
wrappedAssets: Set<string>,
parcelRequireName: string,
|}): Promise<BabelNodeFile> {
let queue = new PromiseQueue({maxConcurrent: 32});
bundle.traverse((node, shouldWrap) => {
Expand Down Expand Up @@ -117,13 +106,6 @@ export async function concat({
let outputs = new Map<string, Array<Statement>>(await queue.run());
let result = [];
if (needsPrelude(bundle, bundleGraph)) {
result.push(
...parse(`var parcelRequireName = "${parcelRequireName}";`, PRELUDE_PATH),
...PRELUDE,
);
}
// Note: for each asset, the order of `$parcel$require` calls and the corresponding
// `asset.getDependencies()` must be the same!
bundle.traverseAssets<TraversalContext>({
Expand Down
30 changes: 17 additions & 13 deletions packages/shared/scope-hoisting/src/formats/commonjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
Identifier,
LVal,
ObjectProperty,
Statement,
VariableDeclaration,
} from '@babel/types';
import type {ExternalBundle, ExternalModule} from '../types';
Expand Down Expand Up @@ -83,7 +84,7 @@ function generateDestructuringAssignment(
specifiers,
value,
scope,
): Array<BabelNode> {
): Array<Statement> {
// If destructuring is not supported, generate a series of variable declarations
// with member expressions for each property.
if (!env.matchesEngines(DESTRUCTURING_ENGINES)) {
Expand Down Expand Up @@ -125,7 +126,7 @@ export function generateBundleImports(
from: NamedBundle,
{bundle, assets}: ExternalBundle,
scope: Scope,
): Array<BabelNode> {
): {|hoisted: Array<Statement>, imports: Array<Statement>|} {
let specifiers: Array<ObjectProperty> = [...assets].map(asset => {
let id = getName(asset, 'init');
return t.objectProperty(t.identifier(id), t.identifier(id), false, true);
Expand All @@ -136,22 +137,25 @@ export function generateBundleImports(
});

if (specifiers.length > 0) {
return generateDestructuringAssignment(
bundle.env,
specifiers,
expression,
scope,
);
return {
imports: generateDestructuringAssignment(
bundle.env,
specifiers,
expression,
scope,
),
hoisted: [],
};
} else {
return [t.expressionStatement(expression)];
return {imports: [t.expressionStatement(expression)], hoisted: []};
}
}

export function generateExternalImport(
bundle: NamedBundle,
external: ExternalModule,
scope: Scope,
): Array<BabelNode> {
): Array<Statement> {
let {source, specifiers, isCommonJS} = external;

let properties: Array<ObjectProperty> = [];
Expand All @@ -177,7 +181,7 @@ export function generateExternalImport(
let specifiersWildcard = specifiers.get('*');
let specifiersDefault = specifiers.get('default');

let statements: Array<BabelNode> = [];
let statements: Array<Statement> = [];
// Attempt to combine require calls as much as possible. Namespace, default, and named specifiers
// cannot be combined, so in the case where we have more than one type, assign the require() result
// to a variable first and then create additional variables for each specifier based on that.
Expand Down Expand Up @@ -298,9 +302,9 @@ export function generateBundleExports(
referencedAssets: Set<Asset>,
scope: Scope,
reexports: Set<{|exportAs: string, local: string|}>,
): Array<BabelNode> {
): Array<Statement> {
let exported = new Set<Symbol>();
let statements: Array<BabelNode> = [];
let statements: Array<Statement> = [];

for (let asset of referencedAssets) {
let id = getIdentifier(asset, 'init');
Expand Down
Loading

0 comments on commit f975010

Please sign in to comment.