diff --git a/packages/astro/package.json b/packages/astro/package.json index d416c3a37..c84c46219 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -56,7 +56,7 @@ "test:match": "mocha --timeout 15000 -g" }, "dependencies": { - "@astrojs/compiler": "^0.11.4", + "@astrojs/compiler": "^0.12.0-next.5", "@astrojs/language-server": "^0.8.6", "@astrojs/markdown-remark": "^0.6.2", "@astrojs/prism": "0.4.0", diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index f8253f36f..e1ba741d4 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -130,6 +130,8 @@ export async function staticBuild(opts: StaticBuildOptions) { const topLevelImports = new Set([ // Any component that gets hydrated ...metadata.hydratedComponentPaths(), + // Client-only components + ...metadata.clientOnlyComponentPaths(), // Any hydration directive like astro/client/idle.js ...metadata.hydrationDirectiveSpecifiers(), // The client path for each renderer @@ -181,6 +183,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp logLevel: 'error', mode: 'production', build: { + ...viteConfig.build, emptyOutDir: false, manifest: ssr, minify: false, diff --git a/packages/astro/src/runtime/server/metadata.ts b/packages/astro/src/runtime/server/metadata.ts index 5343c0301..9fb23724d 100644 --- a/packages/astro/src/runtime/server/metadata.ts +++ b/packages/astro/src/runtime/server/metadata.ts @@ -13,6 +13,7 @@ interface ComponentMetadata { interface CreateMetadataOptions { modules: ModuleInfo[]; hydratedComponents: any[]; + clientOnlyComponents: any[]; hydrationDirectives: Set; hoisted: any[]; } @@ -22,6 +23,7 @@ export class Metadata { public modules: ModuleInfo[]; public hoisted: any[]; public hydratedComponents: any[]; + public clientOnlyComponents: any[]; public hydrationDirectives: Set; private metadataCache: Map; @@ -30,6 +32,7 @@ export class Metadata { this.modules = opts.modules; this.hoisted = opts.hoisted; this.hydratedComponents = opts.hydratedComponents; + this.clientOnlyComponents = opts.clientOnlyComponents; this.hydrationDirectives = opts.hydrationDirectives; this.mockURL = new URL(filePathname, 'http://example.com'); this.metadataCache = new Map(); @@ -66,6 +69,19 @@ export class Metadata { } } + *clientOnlyComponentPaths() { + const found = new Set(); + for (const metadata of this.deepMetadata()) { + for (const component of metadata.clientOnlyComponents) { + const path = metadata.resolvePath(component); + if (path && !found.has(path)) { + found.add(path); + yield path; + } + } + } + } + /** * Gets all of the hydration specifiers used within this component. */ diff --git a/packages/astro/test/astro-assets.test.js b/packages/astro/test/astro-assets.test.js index b80e4d114..9905ff27d 100644 --- a/packages/astro/test/astro-assets.test.js +++ b/packages/astro/test/astro-assets.test.js @@ -13,7 +13,11 @@ describe('Assets', () => { before(async () => { fixture = await loadFixture({ projectRoot: './fixtures/astro-assets/', - buildOptions: { legacyBuild: true } // TODO make this test work without legacyBuild + vite: { + build: { + assetsInlineLimit: 0 + } + } }); await fixture.build(); }); @@ -22,7 +26,7 @@ describe('Assets', () => { const html = await fixture.readFile('/index.html'); const $ = cheerio.load(html); const imgPath = $('img').attr('src'); - const data = await fixture.readFile('/' + imgPath); + const data = await fixture.readFile( imgPath); expect(!!data).to.equal(true); }); @@ -32,7 +36,7 @@ describe('Assets', () => { const srcset = $('img').attr('srcset'); const candidates = matchSrcset(srcset); const match = candidates.find((a) => a.density === 2); - const data = await fixture.readFile('/' + match.url); + const data = await fixture.readFile(match.url); expect(!!data).to.equal(true); }); @@ -42,14 +46,14 @@ describe('Assets', () => { const srcset = $('img').attr('srcset'); const candidates = matchSrcset(srcset); const match = candidates.find((a) => a.density === 3); - const data = await fixture.readFile('/' + match.url); + const data = await fixture.readFile(match.url); expect(!!data).to.equal(true); }); it('built image from an import specifier', async () => { const html = await fixture.readFile('/index.html'); const $ = cheerio.load(html); - const src = '/' + $('#import-no-url').attr('src'); + const src = $('#import-no-url').attr('src'); const data = await fixture.readFile(src); expect(!!data).to.equal(true); }); @@ -57,7 +61,7 @@ describe('Assets', () => { it('built image from an import specifier using ?url', async () => { const html = await fixture.readFile('/index.html'); const $ = cheerio.load(html); - const src = '/' + $('#import-url').attr('src'); + const src = $('#import-url').attr('src'); const data = await fixture.readFile(src); expect(!!data).to.equal(true); }); diff --git a/packages/astro/test/astro-basic.test.js b/packages/astro/test/astro-basic.test.js index 10904b09b..71341a1cc 100644 --- a/packages/astro/test/astro-basic.test.js +++ b/packages/astro/test/astro-basic.test.js @@ -9,7 +9,7 @@ describe('Astro basics', () => { before(async () => { fixture = await loadFixture({ projectRoot: './fixtures/astro-basic/', - buildOptions: { legacyBuild: true } // TODO make this test work without legacyBuild + buildOptions: { legacyBuild: true } }); await fixture.build(); previewServer = await fixture.preview(); diff --git a/packages/astro/test/astro-client-only.test.js b/packages/astro/test/astro-client-only.test.js index 3f3766652..80358ece3 100644 --- a/packages/astro/test/astro-client-only.test.js +++ b/packages/astro/test/astro-client-only.test.js @@ -8,7 +8,6 @@ describe('Client only components', () => { before(async () => { fixture = await loadFixture({ projectRoot: './fixtures/astro-client-only/', - buildOptions: { legacyBuild: true } // TODO make this test work without legacyBuild }); await fixture.build(); }); @@ -19,19 +18,10 @@ describe('Client only components', () => { // test 1: is empty expect($('astro-root').html()).to.equal(''); - const src = $('script').attr('src'); + const $script = $('script'); + const script = $script.html(); - const script = await fixture.readFile(src); // test 2: svelte renderer is on the page - const exp = /import\("(.\/client.*)"\)/g; - let match, svelteRenderer; - while ((match = exp.exec(script))) { - svelteRenderer = match[1].replace(/^\./, '/assets/'); - } - expect(svelteRenderer).to.be.ok; - - // test 3: can load svelte renderer - const svelteClient = await fixture.readFile(svelteRenderer); - expect(svelteClient).to.be.ok; + expect(/import\(".\/PersistentCounter.*/g.test(script)).to.be.ok; }); }); diff --git a/packages/astro/test/astro-components.test.js b/packages/astro/test/astro-components.test.js deleted file mode 100644 index f3a193ae7..000000000 --- a/packages/astro/test/astro-components.test.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * UNCOMMENT: add support for functional components in frontmatter -import { expect } from 'chai'; -import cheerio from 'cheerio'; -import { loadFixture } from './test-utils.js'; - -let fixture; - -before(async () => { - fixture = await loadFixture({ projectRoot: './fixtures/astro-components/' }); - await fixture.build(); -}); - -// TODO: add support for functional components in frontmatter -describe('Components tests', () => { - it('Astro components are able to render framework components', async () => { - const html = await fixture.readFile('/index.html'); - const $ = cheerio.load(html); - - // test 1: Renders Astro component - const $astro = $('#astro'); - expect($astro.children()).to.have.lengthOf(3); - - // test 2: Renders React component - const $react = $('#react'); - expect($react).not.to.have.lengthOf(0); - - // test 3: Renders Vue component - const $vue = $('#vue'); - expect($vue).not.to.have.lengthOf(0); - - // test 4: Renders Svelte component - const $svelte = $('#svelte'); - expect($svelte).not.to.have.lengthOf(0); - }); - - it('Allows Components defined in frontmatter', async () => { - const html = await fixture.readFile('/frontmatter-component/index.html'); - const $ = cheerio.load(html); - - expect($('h1')).to.have.lengthOf(1); - }); - - it('Still throws an error for undefined components', async () => { - const result = await fixture.readFile('/undefined-component/index.html'); - expect(result.status).to.equal(500); - }); - - it('Client attrs not added', async () => { - const html = await fixture.readFile('/client/index.html'); - expect(html).not.to.include(`"client:load": true`); - }); -}); -*/ - -it.skip('is skipped', () => {}); diff --git a/packages/astro/test/astro-scripts.test.js b/packages/astro/test/astro-scripts.test.js index 7be9e97c5..cd54ea768 100644 --- a/packages/astro/test/astro-scripts.test.js +++ b/packages/astro/test/astro-scripts.test.js @@ -9,7 +9,11 @@ describe('Scripts (hoisted and not)', () => { before(async () => { fixture = await loadFixture({ projectRoot: './fixtures/astro-scripts/', - buildOptions: { legacyBuild: true } // TODO make this test work without legacyBuild + vite: { + build: { + assetsInlineLimit: 0 + } + } }); await fixture.build(); }); @@ -41,8 +45,8 @@ describe('Scripts (hoisted and not)', () => { // test 2: attr removed expect($('script').attr('data-astro')).to.equal(undefined); - let entryURL = path.join('inline', $('script').attr('src')); - let inlineEntryJS = await fixture.readFile(entryURL); + const entryURL = $('script').attr('src'); + const inlineEntryJS = await fixture.readFile(entryURL); // test 3: the JS exists expect(inlineEntryJS).to.be.ok; @@ -56,7 +60,7 @@ describe('Scripts (hoisted and not)', () => { expect($('script')).to.have.lengthOf(2); let el = $('script').get(1); - let entryURL = path.join('external', $(el).attr('src')); + let entryURL = $(el).attr('src'); let externalEntryJS = await fixture.readFile(entryURL); // test 2: the JS exists diff --git a/packages/astro/test/cli.test.js b/packages/astro/test/cli.test.js deleted file mode 100644 index 5a767646a..000000000 --- a/packages/astro/test/cli.test.js +++ /dev/null @@ -1,48 +0,0 @@ -import { expect } from 'chai'; -import { cli } from './test-utils.js'; -import { promises as fs } from 'fs'; -import { fileURLToPath } from 'url'; - -describe('astro cli', () => { - it('astro', async () => { - const proc = await cli(); - - expect(proc.stdout).to.include('astro - Futuristic web development tool'); - }); - - it('astro --version', async () => { - const pkgURL = new URL('../package.json', import.meta.url); - const pkgVersion = await fs.readFile(pkgURL, 'utf8').then((data) => JSON.parse(data).version); - - const proc = await cli('--version'); - - expect(proc.stdout).to.equal(pkgVersion); - }); - - it('astro dev', async () => { - const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url); - - const proc = cli('dev', '--project-root', fileURLToPath(projectRootURL)); - - let stdout = ''; - - for await (const chunk of proc.stdout) { - stdout += chunk; - - if (chunk.includes('Local:')) break; - } - - proc.kill(); - - expect(stdout).to.include('Server started'); - }); - - it('astro build', async () => { - const projectRootURL = new URL('./fixtures/astro-basic/', import.meta.url); - - const proc = await cli('build', '--project-root', fileURLToPath(projectRootURL), - '--legacy-build'); - - expect(proc.stdout).to.include('Done'); - }); -}); diff --git a/packages/astro/test/fixtures/astro-assets/src/pages/index.astro b/packages/astro/test/fixtures/astro-assets/src/pages/index.astro index b509f3fb9..341f2744c 100644 --- a/packages/astro/test/fixtures/astro-assets/src/pages/index.astro +++ b/packages/astro/test/fixtures/astro-assets/src/pages/index.astro @@ -9,7 +9,7 @@ import p2Url from '../images/penguin2.jpg?url';

Icons

- +