diff --git a/.changeset/swift-trainers-suffer.md b/.changeset/swift-trainers-suffer.md new file mode 100644 index 000000000..c9f6fc9a8 --- /dev/null +++ b/.changeset/swift-trainers-suffer.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix for copying public when using SSR and not client JS diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index 4e475afb9..afe41a01e 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -169,17 +169,22 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set) { const { astroConfig, viteConfig } = opts; const timer = performance.now(); + const ssr = isBuildingToSSR(astroConfig); + const out = ssr ? opts.buildConfig.client : astroConfig.dist; // Nothing to do if there is no client-side JS. if (!input.size) { + // If SSR, copy public over + if (ssr) { + await copyFiles(astroConfig.public, out); + } + return null; } // TODO: use vite.mergeConfig() here? info(opts.logging, null, `\n${bgGreen(black(' building client '))}`); - const out = isBuildingToSSR(astroConfig) ? opts.buildConfig.client : astroConfig.dist; - const viteBuildConfig = { logLevel: 'info', mode: 'production', @@ -236,6 +241,23 @@ async function cleanSsrOutput(opts: StaticBuildOptions) { ); } +async function copyFiles(fromFolder: URL, toFolder: URL) { + const files = await glob('**/*', { + cwd: fileURLToPath(fromFolder), + }); + + // Make the directory + await fs.promises.mkdir(toFolder, { recursive: true }); + + await Promise.all( + files.map(async (filename) => { + const from = new URL(filename, fromFolder); + const to = new URL(filename, toFolder); + return fs.promises.copyFile(from, to); + }) + ); +} + async function ssrMoveAssets(opts: StaticBuildOptions) { info(opts.logging, 'build', 'Rearranging server assets...'); const serverRoot = opts.buildConfig.staticMode ? opts.buildConfig.client : opts.buildConfig.server; diff --git a/packages/astro/test/fixtures/ssr-request/public/cars.json b/packages/astro/test/fixtures/ssr-request/public/cars.json new file mode 100644 index 000000000..48d4e4d79 --- /dev/null +++ b/packages/astro/test/fixtures/ssr-request/public/cars.json @@ -0,0 +1,7 @@ +[ + { "name": "One" }, + { "name": "Two" }, + { "name": "Three" }, + { "name": "Four" }, + { "name": "Five" } +] diff --git a/packages/astro/test/fixtures/ssr-request/src/pages/request.astro b/packages/astro/test/fixtures/ssr-request/src/pages/request.astro new file mode 100644 index 000000000..ae7cb0187 --- /dev/null +++ b/packages/astro/test/fixtures/ssr-request/src/pages/request.astro @@ -0,0 +1,10 @@ +--- +const origin = new URL(Astro.request.url).origin; +--- + + +Testing + +

{origin}

+ + diff --git a/packages/astro/test/ssr-request.test.js b/packages/astro/test/ssr-request.test.js new file mode 100644 index 000000000..30efb8ef8 --- /dev/null +++ b/packages/astro/test/ssr-request.test.js @@ -0,0 +1,36 @@ + +import { expect } from 'chai'; +import { load as cheerioLoad } from 'cheerio'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; + +// Asset bundling +describe('Using Astro.request in SSR', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + projectRoot: './fixtures/ssr-request/', + buildOptions: { + experimentalSsr: true, + }, + adapter: testAdapter(), + }); + await fixture.build(); + }); + + it('Gets the request pased in', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/request'); + const response = await app.render(request); + const html = await response.text(); + const $ = cheerioLoad(html); + expect($('#origin').text()).to.equal('http://example.com'); + }); + + it('public file is copied over', async () => { + const json = await fixture.readFile('/client/cars.json'); + expect(json).to.not.be.undefined; + }); +});