Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'v2' of github.com:parcel-bundler/parcel into gkong/buil…
Browse files Browse the repository at this point in the history
…d-loop
gorakong committed Jul 26, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 7121ae0 + b29f288 commit 66aeac1
Showing 145 changed files with 2,850 additions and 496 deletions.
4 changes: 1 addition & 3 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -6,9 +6,7 @@
"overrides": [
{
"files": [
"packages/packagers/js/src/prelude.js",
"packages/packagers/swc/src/dev-prelude.js",
"packages/shared/scope-hoisting/src/helpers.js"
"packages/packagers/js/src/dev-prelude.js"
],
"options": {
"trailingComma": "es5"
2 changes: 1 addition & 1 deletion flow-libs/posthtml.js.flow
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ declare module 'posthtml' {
declare type PostHTMLNode = {
tag: string,
attrs?: {[string]: string, ...},
content?: Array<string>,
content?: Array<string | PostHTMLNode>,
location?: {
start: {|line: number, column: number|},
end: {|line: number, column: number|},
8 changes: 1 addition & 7 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -18,16 +18,10 @@ const IGNORED_PACKAGES = [
const paths = {
packageSrc: [
'packages/*/*/src/**/*.js',
'!packages/*/scope-hoisting/src/helpers.js',
'!**/loaders/**',
'!**/prelude.js',
'!**/dev-prelude.js',
...IGNORED_PACKAGES,
],
packageOther: [
'packages/*/scope-hoisting/src/helpers.js',
'packages/*/*/src/**/loaders/**',
'packages/*/*/src/**/prelude.js',
'packages/*/*/src/**/dev-prelude.js',
'packages/*/dev-server/src/templates/**',
],
@@ -76,7 +70,7 @@ exports.default = exports.build = gulp.series(
function buildBabel() {
return gulp
.src(paths.packageSrc)
.pipe(babel(babelConfig))
.pipe(babel({...babelConfig, babelrcRoots: [__dirname + '/packages/*/*']}))
.pipe(renameStream(relative => relative.replace('src', 'lib')))
.pipe(gulp.dest(paths.packages));
}
110 changes: 58 additions & 52 deletions packages/bundlers/default/src/DefaultBundler.js
Original file line number Diff line number Diff line change
@@ -266,58 +266,7 @@ export default (new Bundler({

// Step 3: Remove assets that are duplicated in a parent bundle.
deduplicate(bundleGraph);

// Step 4: Mark async dependencies on assets that are already available in
// the bundle as internally resolvable. This removes the dependency between
// the bundle and the bundle group providing that asset. If all connections
// to that bundle group are removed, remove that bundle group.
let asyncBundleGroups: Set<BundleGroup> = new Set();
bundleGraph.traverse((node, _, actions) => {
if (
node.type !== 'dependency' ||
node.value.isEntry ||
node.value.priority !== 'lazy'
) {
return;
}

if (bundleGraph.isDependencySkipped(node.value)) {
actions.skipChildren();
return;
}

let dependency = node.value;
if (dependency.specifierType === 'url') {
// Don't internalize dependencies on URLs, e.g. `new Worker('foo.js')`
return;
}

let resolution = bundleGraph.getDependencyResolution(dependency);
if (resolution == null) {
return;
}

let externalResolution = bundleGraph.resolveAsyncDependency(dependency);
if (externalResolution?.type === 'bundle_group') {
asyncBundleGroups.add(externalResolution.value);
}

for (let bundle of bundleGraph.findBundlesWithDependency(dependency)) {
if (
bundle.hasAsset(resolution) ||
bundleGraph.isAssetReachableFromBundle(resolution, bundle)
) {
bundleGraph.internalizeAsyncDependency(bundle, dependency);
}
}
});

// Remove any bundle groups that no longer have any parent bundles.
for (let bundleGroup of asyncBundleGroups) {
if (bundleGraph.getParentBundlesOfBundleGroup(bundleGroup).length === 0) {
bundleGraph.removeBundleGroup(bundleGroup);
}
}
internalizeReachableAsyncDependencies(bundleGraph);
},
optimize({bundleGraph, config}) {
// if only one bundle, no need to optimize
@@ -451,6 +400,7 @@ export default (new Bundler({

// Remove assets that are duplicated between shared bundles.
deduplicate(bundleGraph);
internalizeReachableAsyncDependencies(bundleGraph);
},
}): Bundler);

@@ -525,3 +475,59 @@ async function loadBundlerConfig(config: Config, options: PluginOptions) {
conf.contents.maxParallelRequests ?? defaults.maxParallelRequests,
};
}

function internalizeReachableAsyncDependencies(
bundleGraph: MutableBundleGraph,
): void {
// Mark async dependencies on assets that are already available in
// the bundle as internally resolvable. This removes the dependency between
// the bundle and the bundle group providing that asset. If all connections
// to that bundle group are removed, remove that bundle group.
let asyncBundleGroups: Set<BundleGroup> = new Set();
bundleGraph.traverse((node, _, actions) => {
if (
node.type !== 'dependency' ||
node.value.isEntry ||
node.value.priority !== 'lazy'
) {
return;
}

if (bundleGraph.isDependencySkipped(node.value)) {
actions.skipChildren();
return;
}

let dependency = node.value;
if (dependency.specifierType === 'url') {
// Don't internalize dependencies on URLs, e.g. `new Worker('foo.js')`
return;
}

let resolution = bundleGraph.getDependencyResolution(dependency);
if (resolution == null) {
return;
}

let externalResolution = bundleGraph.resolveAsyncDependency(dependency);
if (externalResolution?.type === 'bundle_group') {
asyncBundleGroups.add(externalResolution.value);
}

for (let bundle of bundleGraph.findBundlesWithDependency(dependency)) {
if (
bundle.hasAsset(resolution) ||
bundleGraph.isAssetReachableFromBundle(resolution, bundle)
) {
bundleGraph.internalizeAsyncDependency(bundle, dependency);
}
}
});

// Remove any bundle groups that no longer have any parent bundles.
for (let bundleGroup of asyncBundleGroups) {
if (bundleGraph.getParentBundlesOfBundleGroup(bundleGroup).length === 0) {
bundleGraph.removeBundleGroup(bundleGroup);
}
}
}
44 changes: 42 additions & 2 deletions packages/core/core/src/BundleGraph.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @flow strict-local

import type {
BundleGroup,
GraphVisitor,
FilePath,
Symbol,
TraversalActions,
} from '@parcel/types';
@@ -13,24 +13,28 @@ import type {
AssetNode,
Bundle,
BundleGraphNode,
BundleGroup,
Dependency,
DependencyNode,
NodeId,
InternalSourceLocation,
Target,
} from './types';
import type AssetGraph from './AssetGraph';
import type {ProjectPath} from './projectPath';

import assert from 'assert';
import invariant from 'assert';
import nullthrows from 'nullthrows';
import {objectSortedEntriesDeep} from '@parcel/utils';
import {objectSortedEntriesDeep, getRootDir} from '@parcel/utils';
import {Hash, hashString} from '@parcel/hash';
import {Priority, BundleBehavior} from './types';

import {getBundleGroupId, getPublicId} from './utils';
import {ALL_EDGE_TYPES, mapVisitor} from './Graph';
import ContentGraph, {type SerializedContentGraph} from './ContentGraph';
import {ISOLATED_ENVS} from './public/Environment';
import {fromProjectPath} from './projectPath';

type BundleGraphEdgeTypes =
// A lack of an edge type indicates to follow the edge while traversing
@@ -98,6 +102,7 @@ export default class BundleGraph {
// It needs to be exposed in BundlerRunner for now based on how applying runtimes works and the
// BundlerRunner takes care of invalidating hashes when runtimes are applied, but this is not ideal.
_bundleContentHashes: Map<string, string>;
_targetEntryRoots: Map<ProjectPath, FilePath> = new Map();
_graph: ContentGraph<BundleGraphNode, BundleGraphEdgeTypes>;

constructor({
@@ -450,6 +455,9 @@ export default class BundleGraph {
if (this._graph.hasEdge(bundleNodeId, nodeId, 'references')) {
this._graph.addEdge(bundleNodeId, nodeId, 'references');
}
if (this._graph.hasEdge(bundleNodeId, nodeId, 'internal_async')) {
this._graph.removeEdge(bundleNodeId, nodeId, 'internal_async');
}
}
}, assetNodeId);

@@ -1598,4 +1606,36 @@ export default class BundleGraph {
.map(id => nullthrows(this._graph.getNode(id)))
.some(n => n.type === 'root');
}

getEntryRoot(projectRoot: FilePath, target: Target): FilePath {
let cached = this._targetEntryRoots.get(target.distDir);
if (cached != null) {
return cached;
}

let entryBundleGroupIds = this._graph.getNodeIdsConnectedFrom(
nullthrows(this._graph.rootNodeId),
'bundle',
);

let entries = [];
for (let bundleGroupId of entryBundleGroupIds) {
let bundleGroupNode = this._graph.getNode(bundleGroupId);
invariant(bundleGroupNode?.type === 'bundle_group');

if (bundleGroupNode.value.target.distDir === target.distDir) {
let entryAssetNode = this._graph.getNodeByContentKey(
bundleGroupNode.value.entryAssetId,
);
invariant(entryAssetNode?.type === 'asset');
entries.push(
fromProjectPath(projectRoot, entryAssetNode.value.filePath),
);
}
}

let root = getRootDir(entries);
this._targetEntryRoots.set(target.distDir, root);
return root;
}
}
2 changes: 1 addition & 1 deletion packages/core/core/src/RequestTracker.js
Original file line number Diff line number Diff line change
@@ -558,7 +558,7 @@ export class RequestGraph extends ContentGraph<
// If we see a 'create' event for the project root itself,
// this means the project root was moved and we need to
// re-run all requests.
if (!isInitialBuild && type === 'create' && filePath === '') {
if (isInitialBuild && type === 'create' && filePath === '') {
for (let [id, node] of this.nodes) {
if (node.type === 'request') {
this.invalidNodeIds.add(id);
35 changes: 28 additions & 7 deletions packages/core/core/src/Transformation.js
Original file line number Diff line number Diff line change
@@ -423,14 +423,35 @@ export default class Transformation {
);
}
} catch (e) {
let diagnostic = errorToDiagnostic(e, {
origin: transformer.name,
filePath: fromProjectPath(
this.options.projectRoot,
asset.value.filePath,
),
});

// If this request is a virtual asset that might not exist on the filesystem,
// add the `code` property to each code frame in the diagnostics that match the
// request's filepath. This can't be done by the transformer because it might not
// have access to the original code (e.g. an inline script tag in HTML).
if (this.request.code != null) {
for (let d of diagnostic) {
if (d.codeFrames) {
for (let codeFrame of d.codeFrames) {
if (
codeFrame.code == null &&
codeFrame.filePath === this.request.filePath
) {
codeFrame.code = this.request.code;
}
}
}
}
}

throw new ThrowableDiagnostic({
diagnostic: errorToDiagnostic(e, {
origin: transformer.name,
filePath: fromProjectPath(
this.options.projectRoot,
asset.value.filePath,
),
}),
diagnostic,
});
}
}
20 changes: 12 additions & 8 deletions packages/core/core/src/projectPath.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow strict-local
import type {FilePath} from '@parcel/types';
import path from 'path';
import {relativePath} from '@parcel/utils';
import {relativePath, normalizeSeparators} from '@parcel/utils';

/**
* A path that's relative to the project root.
@@ -18,7 +18,11 @@ function toProjectPath_(projectRoot: FilePath, p: FilePath): ProjectPath {
// references still work. Accessing files outside the project root is not
// portable anyway.
let relative = relativePath(projectRoot, p, false);
return relative.startsWith('..') ? p : relative;
if (relative.startsWith('..')) {
return process.platform === 'win32' ? normalizeSeparators(p) : p;
}

return relative;
}

export const toProjectPath: ((
@@ -34,15 +38,15 @@ function fromProjectPath_(projectRoot: FilePath, p: ?ProjectPath): ?FilePath {
return null;
}

// If the path is absolute (e.g. outside the project root), just return it.
if (path.isAbsolute(p)) {
return p;
}

// Project paths use normalized unix separators, so we only need to
// convert them on Windows.
let projectPath = process.platform === 'win32' ? path.normalize(p) : p;

// If the path is absolute (e.g. outside the project root), just return it.
if (path.isAbsolute(projectPath)) {
return projectPath;
}

// Add separator if needed. Doing this manunally is much faster than path.join.
if (projectRoot[projectRoot.length - 1] !== path.sep) {
return projectRoot + path.sep + projectPath;
@@ -79,5 +83,5 @@ export function joinProjectPath(
a: ProjectPath,
...b: Array<FilePath>
): ProjectPath {
return path.join(a, ...b);
return path.posix.join(a, ...b);
}
Loading

0 comments on commit 66aeac1

Please sign in to comment.