Skip to content

Commit

Permalink
Add no-op tier import API
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeLane committed Jul 23, 2024
1 parent f58a5e8 commit aa394b2
Show file tree
Hide file tree
Showing 29 changed files with 449 additions and 108 deletions.
2 changes: 2 additions & 0 deletions crates/parcel_core/src/types/dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ pub enum Priority {
Parallel = 1,
/// The dependency should be placed in a separate bundle that is loaded later
Lazy = 2,
/// The dependency should be deferred to a different tier
Tier = 3,
}

impl Default for Priority {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub(crate) fn convert_priority(
DependencyKind::Export => Priority::Sync,
DependencyKind::Require => Priority::Sync,
DependencyKind::File => Priority::Sync,
DependencyKind::DeferredForDisplayTierImport => Priority::Tier,
DependencyKind::DeferredTierImport => Priority::Tier,
}
}

Expand All @@ -33,6 +35,8 @@ pub(crate) fn convert_specifier_type(
DependencyKind::Worklet => SpecifierType::Url,
DependencyKind::Url => SpecifierType::Url,
DependencyKind::File => SpecifierType::Custom,
DependencyKind::DeferredForDisplayTierImport => SpecifierType::Esm,
DependencyKind::DeferredTierImport => SpecifierType::Esm,
}
}

Expand Down
9 changes: 6 additions & 3 deletions packages/bundlers/default/src/DefaultBundler.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const dependencyPriorityEdges = {
sync: 1,
parallel: 2,
lazy: 3,
tier: 4,
};

type DependencyBundleGraph = ContentGraph<
Expand Down Expand Up @@ -277,7 +278,8 @@ function decorateLegacyGraph(
);
for (let incomingDep of incomingDeps) {
if (
incomingDep.priority === 'lazy' &&
(incomingDep.priority === 'lazy' ||
incomingDep.priority === 'tier') &&
incomingDep.specifierType !== 'url' &&
bundle.hasDependency(incomingDep)
) {
Expand All @@ -294,7 +296,7 @@ function decorateLegacyGraph(
let incomingDeps = bundleGraph.getIncomingDependencies(manualSharedAsset);
for (let incomingDep of incomingDeps) {
if (
incomingDep.priority === 'lazy' &&
(incomingDep.priority === 'lazy' || incomingDep.priority === 'tier') &&
incomingDep.specifierType !== 'url'
) {
let bundles = bundleGraph.getBundlesWithDependency(incomingDep);
Expand Down Expand Up @@ -495,7 +497,7 @@ function createIdealGraph(

if (
node.type === 'dependency' &&
node.value.priority === 'lazy' &&
(node.value.priority === 'lazy' || node.value.priority === 'tier') &&
parentAsset
) {
// Don't walk past the bundle group assets
Expand Down Expand Up @@ -584,6 +586,7 @@ function createIdealGraph(
}
if (
dependency.priority === 'lazy' ||
dependency.priority === 'tier' ||
childAsset.bundleBehavior === 'isolated' // An isolated Dependency, or Bundle must contain all assets it needs to load.
) {
if (bundleId == null) {
Expand Down
1 change: 1 addition & 0 deletions packages/core/core/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export const Priority = {
sync: 0,
parallel: 1,
lazy: 2,
tier: 3,
};

// Must match package_json.rs in node-resolver-rs.
Expand Down
1 change: 1 addition & 0 deletions packages/core/core/test/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const DEFAULT_OPTIONS: ParcelOptions = {
exampleFeature: false,
configKeyInvalidation: false,
parcelV3: false,
tieredImports: false,
},
};

Expand Down
1 change: 1 addition & 0 deletions packages/core/feature-flags/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const DEFAULT_FEATURE_FLAGS: FeatureFlags = {
exampleFeature: false,
configKeyInvalidation: false,
parcelV3: false,
tieredImports: false,
};

let featureFlagValues: FeatureFlags = {...DEFAULT_FEATURE_FLAGS};
Expand Down
4 changes: 4 additions & 0 deletions packages/core/feature-flags/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ export type FeatureFlags = {|
* Rust backed requests
*/
+parcelV3: boolean,
/**
* Tiered imports API
*/
+tieredImports: boolean,
|};
2 changes: 1 addition & 1 deletion packages/core/types-internal/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ export interface MutableDependencySymbols // eslint-disable-next-line no-undef
delete(exportSymbol: Symbol): void;
}

export type DependencyPriority = 'sync' | 'parallel' | 'lazy';
export type DependencyPriority = 'sync' | 'parallel' | 'lazy' | 'tier';
export type SpecifierType = 'commonjs' | 'esm' | 'url' | 'custom';

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/examples/phases/.parcelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "@parcel/config-default"
}
20 changes: 20 additions & 0 deletions packages/examples/phases/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@parcel/phases-example",
"version": "2.12.0",
"license": "MIT",
"private": true,
"scripts": {
"start": "parcel serve src/index.html --no-cache --https --feature-flag tieredImports=true",
"start:prod": "yarn build && npx http-server dist/",
"build": "PARCEL_WORKERS=0 parcel build src/index.html --no-cache --feature-flag tieredImports=true",
"debug": "PARCEL_WORKERS=0 node --inspect-brk $(yarn bin parcel) serve src/index.html --no-cache --https --feature-flag tieredImports=true --no-hmr",
"debug:prod": "PARCEL_WORKERS=0 node --inspect-brk $(yarn bin parcel) build src/index.html --no-cache --feature-flag tieredImports=true"
},
"devDependencies": {
"parcel": "2.12.0"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
}
15 changes: 15 additions & 0 deletions packages/examples/phases/phases.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type ModuleRef<_> = string;
type ErrorMessage = 'You must annotate type with "<typeof import(\'xyz\')>"';

interface DeferredImport<T> {
onReady(resource: () => void): () => void;
mod: T | null;
}

declare function importDeferredForDisplay<T extends any | void = void>(
source: T extends void ? ErrorMessage : ModuleRef<T>,
): DeferredImport<T>;

declare function importDeferred<T extends any | void = void>(
source: T extends void ? ErrorMessage : ModuleRef<T>,
): DeferredImport<T>;
14 changes: 14 additions & 0 deletions packages/examples/phases/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Parcel | React Phases</title>
</head>
<body>
<div id="app"></div>

<script src="./index.tsx" type="module"></script>
</body>
</html>
28 changes: 28 additions & 0 deletions packages/examples/phases/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, {FC, Suspense, useEffect} from 'react';
import ReactDOM from 'react-dom';

import ModulePhase1 from './phase1';
import {deferredLoadComponent} from './utils';
const Phase2 = deferredLoadComponent(
importDeferredForDisplay<typeof import('./phase2')>('./phase2'),
);
const Phase3 = deferredLoadComponent(
importDeferred<typeof import('./phase3')>('./phase3'),
);

function App() {
return (
<>
<div>App</div>
<ModulePhase1 />
<Suspense fallback={<div>Loading...</div>}>
<Phase2 />
</Suspense>
<Suspense fallback={<div>Loading...</div>}>
<Phase3 />
</Suspense>
</>
);
}

ReactDOM.render(<App />, document.getElementById('app'));
5 changes: 5 additions & 0 deletions packages/examples/phases/src/lazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';

const Lazy = () => <div>Lazy</div>;

export default Lazy;
5 changes: 5 additions & 0 deletions packages/examples/phases/src/phase1.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';

const Phase1 = () => <div>Phase 1</div>;

export default Phase1;
5 changes: 5 additions & 0 deletions packages/examples/phases/src/phase2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';

const ModulePhase2 = () => <div>Phase 2</div>;

export default ModulePhase2;
5 changes: 5 additions & 0 deletions packages/examples/phases/src/phase3.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';

const ModulePhase3 = () => <div>Phase 3</div>;

export default ModulePhase3;
25 changes: 25 additions & 0 deletions packages/examples/phases/src/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, {FC, useEffect} from 'react';

export function deferredLoadComponent<T>(
Resource: DeferredImport<T extends {default: any} ? T : never>,
): FC {
let loaded = false;
let cleanUp: undefined | (() => void);
return function WrappedComponent(props) {
useEffect(() => {
return () => {
cleanUp?.();
};
}, []);
if (loaded) {
return <Resource.mod.default {...props} />;
} else {
throw new Promise(resolve => {
cleanUp = Resource.onReady(() => {
loaded = true;
resolve(Resource);
});
});
}
};
}
8 changes: 8 additions & 0 deletions packages/examples/phases/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"typeRoots": ["phases.d.ts"],
"jsx": "react",
"lib": ["ESNext", "DOM"],
"esModuleInterop": true
}
}
1 change: 1 addition & 0 deletions packages/packagers/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"dependencies": {
"@parcel/diagnostic": "2.12.0",
"@parcel/feature-flags": "2.12.0",
"@parcel/plugin": "2.12.0",
"@parcel/rust": "2.12.0",
"@parcel/source-map": "^2.1.1",
Expand Down
Loading

0 comments on commit aa394b2

Please sign in to comment.