diff --git a/.changeset/real-drinks-melt.md b/.changeset/real-drinks-melt.md new file mode 100644 index 000000000..648ef1d91 --- /dev/null +++ b/.changeset/real-drinks-melt.md @@ -0,0 +1,30 @@ +--- +'astro': minor +--- + +Improved hoisted script bundling + +Astro's static analysis to determine which ` \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/components/B.astro b/packages/astro/test/fixtures/hoisted-imports/src/components/B.astro new file mode 100644 index 000000000..48e567703 --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/components/B.astro @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/components/C.astro b/packages/astro/test/fixtures/hoisted-imports/src/components/C.astro new file mode 100644 index 000000000..ec8b281af --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/components/C.astro @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/components/CWrapper.astro b/packages/astro/test/fixtures/hoisted-imports/src/components/CWrapper.astro new file mode 100644 index 000000000..04345e8da --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/components/CWrapper.astro @@ -0,0 +1,5 @@ +--- +import C from './C.astro'; +--- + + \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/components/D.astro b/packages/astro/test/fixtures/hoisted-imports/src/components/D.astro new file mode 100644 index 000000000..0863f8c0d --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/components/D.astro @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/components/E.astro b/packages/astro/test/fixtures/hoisted-imports/src/components/E.astro new file mode 100644 index 000000000..9c56556e5 --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/components/E.astro @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/components/index.ts b/packages/astro/test/fixtures/hoisted-imports/src/components/index.ts new file mode 100644 index 000000000..a0fea55b0 --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/components/index.ts @@ -0,0 +1,9 @@ +import A_aliased from './A.astro'; +import { default as C_aliased } from './CWrapper.astro'; +import D from './D.astro'; +import E_aliased from './E.astro'; + +export { A_aliased as A, C_aliased as C_aliased }; +export { default as B2 } from './B.astro'; +export const D_aliased = D; +export default E_aliased; diff --git a/packages/astro/test/fixtures/hoisted-imports/src/pages/all.astro b/packages/astro/test/fixtures/hoisted-imports/src/pages/all.astro new file mode 100644 index 000000000..bae62dfdd --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/pages/all.astro @@ -0,0 +1,12 @@ +--- +import E, { A, B2, C_aliased, D_aliased } from '../components'; +--- + + + + + + + + + \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/pages/dynamic.astro b/packages/astro/test/fixtures/hoisted-imports/src/pages/dynamic.astro new file mode 100644 index 000000000..4408a8f48 --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/pages/dynamic.astro @@ -0,0 +1,4 @@ +--- +import('../components/index'); +--- + \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/pages/none.astro b/packages/astro/test/fixtures/hoisted-imports/src/pages/none.astro new file mode 100644 index 000000000..991ba42f2 --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/pages/none.astro @@ -0,0 +1,7 @@ +--- +import '../components'; +--- + + + + \ No newline at end of file diff --git a/packages/astro/test/fixtures/hoisted-imports/src/pages/some.astro b/packages/astro/test/fixtures/hoisted-imports/src/pages/some.astro new file mode 100644 index 000000000..e5321a8b1 --- /dev/null +++ b/packages/astro/test/fixtures/hoisted-imports/src/pages/some.astro @@ -0,0 +1,9 @@ +--- +import { A, C_aliased as C } from '../components'; +--- + + + + + + diff --git a/packages/astro/test/hoisted-imports.test.js b/packages/astro/test/hoisted-imports.test.js new file mode 100644 index 000000000..973d7103e --- /dev/null +++ b/packages/astro/test/hoisted-imports.test.js @@ -0,0 +1,92 @@ +import { expect } from 'chai'; +import { loadFixture } from './test-utils.js'; +import * as cheerio from 'cheerio'; + +describe('Hoisted Imports', () => { + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/hoisted-imports/', + }); + }); + + async function getAllScriptText(page) { + const html = await fixture.readFile(page); + const $ = cheerio.load(html); + const scriptText = []; + + const importRegex = /import\s*?['"]([^'"]+?)['"]/g; + async function resolveImports(text) { + const matches = text.matchAll(importRegex); + for (const match of matches) { + const importPath = match[1]; + const importText = await fixture.readFile('/_astro/' + importPath); + scriptText.push(await resolveImports(importText)); + } + return text; + } + + const scripts = $('script'); + for (let i = 0; i < scripts.length; i++) { + const src = scripts.eq(i).attr('src'); + + let text; + if (src) { + text = await fixture.readFile(src); + } else { + text = scripts.eq(i).text(); + } + scriptText.push(await resolveImports(text)); + } + return scriptText.join('\n'); + } + + describe('build', () => { + before(async () => { + await fixture.build(); + }); + + function expectScript(scripts, letter) { + const regex = new RegExp(`console.log\\(['"]${letter}['"]\\)`); + expect(scripts, 'missing component ' + letter).to.match(regex); + } + function expectNotScript(scripts, letter) { + const regex = new RegExp(`console.log\\(['"]${letter}['"]\\)`); + expect(scripts, "shouldn't include component " + letter).to.not.match(regex); + } + + it('includes all imported scripts', async () => { + const scripts = await getAllScriptText('/all/index.html'); + expectScript(scripts, 'A'); + expectScript(scripts, 'B'); + expectScript(scripts, 'C'); + expectScript(scripts, 'D'); + expectScript(scripts, 'E'); + }); + it('includes all imported scripts when dynamically imported', async () => { + const scripts = await getAllScriptText('/dynamic/index.html'); + expectScript(scripts, 'A'); + expectScript(scripts, 'B'); + expectScript(scripts, 'C'); + expectScript(scripts, 'D'); + expectScript(scripts, 'E'); + }); + it('includes no scripts when none imported', async () => { + const scripts = await getAllScriptText('/none/index.html'); + expectNotScript(scripts, 'A'); + expectNotScript(scripts, 'B'); + expectNotScript(scripts, 'C'); + expectNotScript(scripts, 'D'); + expectNotScript(scripts, 'E'); + }); + it('includes some scripts', async () => { + const scripts = await getAllScriptText('/some/index.html'); + expectScript(scripts, 'A'); + expectNotScript(scripts, 'B'); + expectScript(scripts, 'C'); + expectNotScript(scripts, 'D'); + expectNotScript(scripts, 'E'); + }); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 847dfb9a0..7736ea099 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2679,6 +2679,12 @@ importers: specifier: workspace:* version: link:../../.. + packages/astro/test/fixtures/hoisted-imports: + dependencies: + astro: + specifier: workspace:* + version: link:../../.. + packages/astro/test/fixtures/html-component: dependencies: astro: