diff --git a/packages/core/core/src/requests/AssetGraphRequest.js b/packages/core/core/src/requests/AssetGraphRequest.js index 0895418ac59..2790c5a10cf 100644 --- a/packages/core/core/src/requests/AssetGraphRequest.js +++ b/packages/core/core/src/requests/AssetGraphRequest.js @@ -369,6 +369,13 @@ export class AssetGraphBuilder { if (!previouslyDeferred && childNode.deferred) { this.assetGraph.markParentsWithHasDeferred(childNodeId); } else if (previouslyDeferred && !childNode.deferred) { + // Mark Asset and Dependency as dirty for symbol propagation as it was + // previously deferred and it's used symbols may have changed + this.changedAssetsPropagation.add(node.id); + node.usedSymbolsDownDirty = true; + this.changedAssetsPropagation.add(childNode.id); + childNode.usedSymbolsDownDirty = true; + this.assetGraph.unmarkParentsWithHasDeferred(childNodeId); } diff --git a/packages/core/integration-tests/test/lazy-compile.js b/packages/core/integration-tests/test/lazy-compile.js index ac431fb91f6..6f72b57d0cf 100644 --- a/packages/core/integration-tests/test/lazy-compile.js +++ b/packages/core/integration-tests/test/lazy-compile.js @@ -8,10 +8,23 @@ import { assertBundles, removeDistDirectory, run, + fsFixture, + overlayFS, } from '@parcel/test-utils'; const findBundle = (bundleGraph, nameRegex) => { - return bundleGraph.getBundles().find(b => nameRegex.test(b.name)); + const result = bundleGraph.getBundles().find(b => nameRegex.test(b.name)); + + if (!result) { + throw new Error( + `Couldn't find bundle matching '${nameRegex}'. Available bundles are ${bundleGraph + ?.getBundles() + .map(b => b.name) + .join(', ')}`, + ); + } + + return result; }; const distDirIncludes = async matches => { @@ -261,4 +274,73 @@ describe('lazy compile', function () { ]); subscription.unsubscribe(); }); + + it('should lazy compile properly when an assets needs to be re-visited in symbol propagation', async () => { + await fsFixture(overlayFS, __dirname)` + lazy-compile-import-symbols + index.js: + import { shared, async } from './main'; + export default Promise.all([shared(), async()]); + + main.js: + export function shared() { + return import('./shared'); + } + export function async() { + return import('./async'); + } + + async.js: + // Trigger more deps so a full 'propagateSymbolsUp' pass is executed + import './a'; + import './b'; + import './c'; + import { other } from './shared'; + export default other; + + shared.js: + export const main = 'main'; + export const other = 'other'; + + a.js: + sideEffectNoop(); + b.js: + sideEffectNoop(); + c.js: + sideEffectNoop(); + `; + + const b = await bundler( + path.join(__dirname, 'lazy-compile-import-symbols/index.js'), + { + shouldBuildLazily: true, + mode: 'development', + shouldContentHash: false, + inputFS: overlayFS, + }, + ); + + await removeDistDirectory(); + + const subscription = await b.watch(); + let result = await getNextBuild(b); + result = await result.requestBundle( + findBundle(result.bundleGraph, /^index\.js/), + ); + result = await result.requestBundle( + findBundle(result.bundleGraph, /^async\./), + ); + + let output = await run(result.bundleGraph); + assert.deepEqual(await output.default, [ + { + main: 'main', + other: 'other', + }, + { + default: 'other', + }, + ]); + subscription.unsubscribe(); + }); });