Handle project folders containing a space in the static build (#2486)

* Handle project folders containing a space

* Adds a changeset

* Bump the test package version

* Use server relative paths as entries

* Fix windows

* A hoisted fix

* Correctly handle facadeIds on windows
This commit is contained in:
Matthew Phillips 2022-01-28 20:29:28 -05:00 committed by GitHub
parent b3e0b80ab6
commit 6bd165f84c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 31 additions and 18 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix for the static build when project contains a space

View file

@ -63,7 +63,7 @@
"packages/astro/test/fixtures/builtins/packages/*", "packages/astro/test/fixtures/builtins/packages/*",
"packages/astro/test/fixtures/builtins-polyfillnode", "packages/astro/test/fixtures/builtins-polyfillnode",
"packages/astro/test/fixtures/custom-elements/my-component-lib", "packages/astro/test/fixtures/custom-elements/my-component-lib",
"packages/astro/test/fixtures/static-build/pkg" "packages/astro/test/fixtures/static build/pkg"
], ],
"volta": { "volta": {
"node": "14.17.0", "node": "14.17.0",

View file

@ -14,6 +14,7 @@ import { fileURLToPath } from 'url';
import glob from 'fast-glob'; import glob from 'fast-glob';
import vite from '../vite.js'; import vite from '../vite.js';
import { debug, error } from '../../core/logger.js'; import { debug, error } from '../../core/logger.js';
import { prependForwardSlash } from '../../core/path.js';
import { createBuildInternals } from '../../core/build/internal.js'; import { createBuildInternals } from '../../core/build/internal.js';
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js'; import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
import { getParamsAndProps } from '../ssr/index.js'; import { getParamsAndProps } from '../ssr/index.js';
@ -40,12 +41,16 @@ function addPageName(pathname: string, opts: StaticBuildOptions): void {
} }
// Determines of a Rollup chunk is an entrypoint page. // Determines of a Rollup chunk is an entrypoint page.
function chunkIsPage(output: OutputAsset | OutputChunk, internals: BuildInternals) { function chunkIsPage(astroConfig: AstroConfig, output: OutputAsset | OutputChunk, internals: BuildInternals) {
if (output.type !== 'chunk') { if (output.type !== 'chunk') {
return false; return false;
} }
const chunk = output as OutputChunk; const chunk = output as OutputChunk;
return chunk.facadeModuleId && (internals.entrySpecifierToBundleMap.has(chunk.facadeModuleId) || internals.entrySpecifierToBundleMap.has('/' + chunk.facadeModuleId)); if(chunk.facadeModuleId) {
const facadeToEntryId = prependForwardSlash(chunk.facadeModuleId.slice(fileURLToPath(astroConfig.projectRoot).length));
return internals.entrySpecifierToBundleMap.has(facadeToEntryId);
}
return false;
} }
// Throttle the rendering a paths to prevents creating too many Promises on the microtask queue. // Throttle the rendering a paths to prevents creating too many Promises on the microtask queue.
@ -74,8 +79,8 @@ function* throttle(max: number, inPaths: string[]) {
function getByFacadeId<T>(facadeId: string, map: Map<string, T>): T | undefined { function getByFacadeId<T>(facadeId: string, map: Map<string, T>): T | undefined {
return ( return (
map.get(facadeId) || map.get(facadeId) ||
// Check with a leading `/` because on Windows it doesn't have one. // Windows the facadeId has forward slashes, no idea why
map.get('/' + facadeId) map.get(facadeId.replace(/\//g, '\\'))
); );
} }
@ -105,7 +110,7 @@ export async function staticBuild(opts: StaticBuildOptions) {
for (const [component, pageData] of Object.entries(allPages)) { for (const [component, pageData] of Object.entries(allPages)) {
const astroModuleURL = new URL('./' + component, astroConfig.projectRoot); const astroModuleURL = new URL('./' + component, astroConfig.projectRoot);
const astroModuleId = astroModuleURL.pathname; const astroModuleId = prependForwardSlash(component);
const [renderers, mod] = pageData.preload; const [renderers, mod] = pageData.preload;
const metadata = mod.$$metadata; const metadata = mod.$$metadata;
@ -121,7 +126,7 @@ export async function staticBuild(opts: StaticBuildOptions) {
// Add hoisted scripts // Add hoisted scripts
const hoistedScripts = new Set(metadata.hoistedScriptPaths()); const hoistedScripts = new Set(metadata.hoistedScriptPaths());
if (hoistedScripts.size) { if (hoistedScripts.size) {
const moduleId = new URL('./hoisted.js', astroModuleURL + '/').pathname; const moduleId = npath.posix.join(astroModuleId, 'hoisted.js');
internals.hoistedScriptIdToHoistedMap.set(moduleId, hoistedScripts); internals.hoistedScriptIdToHoistedMap.set(moduleId, hoistedScripts);
topLevelImports.add(moduleId); topLevelImports.add(moduleId);
} }
@ -131,7 +136,7 @@ export async function staticBuild(opts: StaticBuildOptions) {
} }
pageInput.add(astroModuleId); pageInput.add(astroModuleId);
facadeIdToPageDataMap.set(astroModuleId, pageData); facadeIdToPageDataMap.set(fileURLToPath(astroModuleURL), pageData);
} }
// Empty out the dist folder, if needed. Vite has a config for doing this // Empty out the dist folder, if needed. Vite has a config for doing this
@ -177,7 +182,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
root: viteConfig.root, root: viteConfig.root,
envPrefix: 'PUBLIC_', envPrefix: 'PUBLIC_',
server: viteConfig.server, server: viteConfig.server,
base: astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/', base: astroConfig.buildOptions.site ? fileURLToPath(new URL(astroConfig.buildOptions.site)) : '/',
ssr: viteConfig.ssr, ssr: viteConfig.ssr,
} as ViteConfigWithSSR); } as ViteConfigWithSSR);
} }
@ -208,7 +213,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
}, },
plugins: [ plugins: [
vitePluginNewBuild(input, internals, 'js'), vitePluginNewBuild(input, internals, 'js'),
vitePluginHoistedScripts(internals), vitePluginHoistedScripts(astroConfig, internals),
rollupPluginAstroBuildCSS({ rollupPluginAstroBuildCSS({
internals, internals,
}), }),
@ -218,7 +223,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
root: viteConfig.root, root: viteConfig.root,
envPrefix: 'PUBLIC_', envPrefix: 'PUBLIC_',
server: viteConfig.server, server: viteConfig.server,
base: astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/', base: astroConfig.buildOptions.site ? fileURLToPath(new URL(astroConfig.buildOptions.site)) : '/',
}); });
} }
@ -257,7 +262,7 @@ async function generatePages(result: RollupOutput, opts: StaticBuildOptions, int
const generationPromises = []; const generationPromises = [];
for (let output of result.output) { for (let output of result.output) {
if (chunkIsPage(output, internals)) { if (chunkIsPage(opts.astroConfig, output, internals)) {
generationPromises.push(generatePage(output as OutputChunk, opts, internals, facadeIdToPageDataMap, renderers)); generationPromises.push(generatePage(output as OutputChunk, opts, internals, facadeIdToPageDataMap, renderers));
} }
} }
@ -272,7 +277,7 @@ async function generatePage(output: OutputChunk, opts: StaticBuildOptions, inter
let pageData = getByFacadeId<PageBuildData>(facadeId, facadeIdToPageDataMap); let pageData = getByFacadeId<PageBuildData>(facadeId, facadeIdToPageDataMap);
if (!pageData) { if (!pageData) {
throw new Error(`Unable to find a PageBuildData for the Astro page: ${facadeId}. There are the PageBuilDatas we have ${Array.from(facadeIdToPageDataMap.keys()).join(', ')}`); throw new Error(`Unable to find a PageBuildData for the Astro page: ${facadeId}. There are the PageBuildDatas we have ${Array.from(facadeIdToPageDataMap.keys()).join(', ')}`);
} }
const linkIds = getByFacadeId<string[]>(facadeId, internals.facadeIdToAssetsMap) || []; const linkIds = getByFacadeId<string[]>(facadeId, internals.facadeIdToAssetsMap) || [];
@ -383,7 +388,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
async function cleanSsrOutput(opts: StaticBuildOptions) { async function cleanSsrOutput(opts: StaticBuildOptions) {
// The SSR output is all .mjs files, the client output is not. // The SSR output is all .mjs files, the client output is not.
const files = await glob('**/*.mjs', { const files = await glob('**/*.mjs', {
cwd: opts.astroConfig.dist.pathname, cwd: fileURLToPath(opts.astroConfig.dist),
}); });
await Promise.all( await Promise.all(
files.map(async (filename) => { files.map(async (filename) => {

View file

@ -1,11 +1,13 @@
import type { AstroConfig } from '../../@types/astro';
import type { Plugin as VitePlugin } from '../vite'; import type { Plugin as VitePlugin } from '../vite';
import type { BuildInternals } from '../../core/build/internal.js'; import type { BuildInternals } from '../../core/build/internal.js';
import { fileURLToPath } from 'url';
function virtualHoistedEntry(id: string) { function virtualHoistedEntry(id: string) {
return id.endsWith('.astro/hoisted.js') || id.endsWith('.md/hoisted.js'); return id.endsWith('.astro/hoisted.js') || id.endsWith('.md/hoisted.js');
} }
export function vitePluginHoistedScripts(internals: BuildInternals): VitePlugin { export function vitePluginHoistedScripts(astroConfig: AstroConfig, internals: BuildInternals): VitePlugin {
return { return {
name: '@astro/rollup-plugin-astro-hoisted-scripts', name: '@astro/rollup-plugin-astro-hoisted-scripts',
@ -34,7 +36,8 @@ export function vitePluginHoistedScripts(internals: BuildInternals): VitePlugin
for (const [id, output] of Object.entries(bundle)) { for (const [id, output] of Object.entries(bundle)) {
if (output.type === 'chunk' && output.facadeModuleId && virtualHoistedEntry(output.facadeModuleId)) { if (output.type === 'chunk' && output.facadeModuleId && virtualHoistedEntry(output.facadeModuleId)) {
const facadeId = output.facadeModuleId!; const facadeId = output.facadeModuleId!;
const filename = facadeId.slice(0, facadeId.length - '/hoisted.js'.length); const pathname = facadeId.slice(0, facadeId.length - '/hoisted.js'.length);
const filename = fileURLToPath(new URL('.' + pathname, astroConfig.projectRoot));
internals.facadeIdToHoistedEntryMap.set(filename, id); internals.facadeIdToHoistedEntryMap.set(filename, id);
} }
} }

View file

@ -1,7 +1,7 @@
{ {
"name": "@astrojs/test-static-build-pkg", "name": "@astrojs/test-static-build-pkg",
"main": "./oops.js", "main": "./oops.js",
"version": "0.0.1", "version": "0.0.2",
"exports": { "exports": {
".": { ".": {
"import": "./pkg.js", "import": "./pkg.js",

View file

@ -11,7 +11,7 @@ describe('Static build', () => {
before(async () => { before(async () => {
fixture = await loadFixture({ fixture = await loadFixture({
projectRoot: './fixtures/static-build/', projectRoot: './fixtures/static build/',
renderers: ['@astrojs/renderer-preact'], renderers: ['@astrojs/renderer-preact'],
buildOptions: { buildOptions: {
experimentalStaticBuild: true, experimentalStaticBuild: true,