0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

fix custom assetFileNames issue (#12449)

* fix custom assetFileNames issue

* fix error

* fix asset name

* handle edge cases fo multiple asset dirs

* add tests

* format

* add changeset

* improve changeset

* add missing files for tests

* Update neat-papayas-brake.md

improve changeset
This commit is contained in:
Arpan Patel 2024-12-04 10:49:22 -06:00 committed by GitHub
parent 350b3da9cf
commit e6b8017239
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 43 additions and 32 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes an issue where the custom `assetFileNames` configuration caused assets to be incorrectly moved to the server directory instead of the client directory, resulting in 404 errors when accessed from the client side.

View file

@ -211,7 +211,7 @@ class AstroBuilder {
key: keyPromise, key: keyPromise,
}; };
const { internals, ssrOutputChunkNames, contentFileNames } = await viteBuild(opts); const { internals, ssrOutputChunkNames, ssrOutputAssetNames, contentFileNames } = await viteBuild(opts);
const hasServerIslands = this.settings.serverIslandNameMap.size > 0; const hasServerIslands = this.settings.serverIslandNameMap.size > 0;
// Error if there are server islands but no adapter provided. // Error if there are server islands but no adapter provided.
@ -219,7 +219,7 @@ class AstroBuilder {
throw new AstroError(AstroErrorData.NoAdapterInstalledServerIslands); throw new AstroError(AstroErrorData.NoAdapterInstalledServerIslands);
} }
await staticBuild(opts, internals, ssrOutputChunkNames, contentFileNames); await staticBuild(opts, internals, ssrOutputChunkNames, ssrOutputAssetNames, contentFileNames);
// Write any additionally generated assets to disk. // Write any additionally generated assets to disk.
this.timer.assetsStart = performance.now(); this.timer.assetsStart = performance.now();

View file

@ -104,21 +104,26 @@ export async function viteBuild(opts: StaticBuildOptions) {
// For static builds, the SSR output won't be needed anymore after page generation. // For static builds, the SSR output won't be needed anymore after page generation.
// We keep track of the names here so we only remove these specific files when finished. // We keep track of the names here so we only remove these specific files when finished.
const ssrOutputChunkNames: string[] = []; const ssrOutputChunkNames: string[] = [];
const ssrOutputAssetNames: string[] = [];
for (const output of ssrOutputs) { for (const output of ssrOutputs) {
for (const chunk of output.output) { for (const chunk of output.output) {
if (chunk.type === 'chunk') { if (chunk.type === 'chunk') {
ssrOutputChunkNames.push(chunk.fileName); ssrOutputChunkNames.push(chunk.fileName);
} }
if (chunk.type === 'asset') {
ssrOutputAssetNames.push(chunk.fileName);
}
} }
} }
return { internals, ssrOutputChunkNames, contentFileNames }; return { internals, ssrOutputChunkNames, ssrOutputAssetNames, contentFileNames };
} }
export async function staticBuild( export async function staticBuild(
opts: StaticBuildOptions, opts: StaticBuildOptions,
internals: BuildInternals, internals: BuildInternals,
ssrOutputChunkNames: string[], ssrOutputChunkNames: string[],
ssrOutputAssetNames: string[],
contentFileNames?: string[], contentFileNames?: string[],
) { ) {
const { settings } = opts; const { settings } = opts;
@ -131,7 +136,7 @@ export async function staticBuild(
settings.timer.start('Server generate'); settings.timer.start('Server generate');
await generatePages(opts, internals); await generatePages(opts, internals);
await cleanStaticOutput(opts, internals); await cleanStaticOutput(opts, internals);
await ssrMoveAssets(opts); await ssrMoveAssets(opts, ssrOutputAssetNames);
settings.timer.end('Server generate'); settings.timer.end('Server generate');
} }
} }
@ -412,33 +417,26 @@ export async function copyFiles(fromFolder: URL, toFolder: URL, includeDotfiles
); );
} }
async function ssrMoveAssets(opts: StaticBuildOptions) { async function ssrMoveAssets(opts: StaticBuildOptions, ssrOutputAssetNames: string[]) {
opts.logger.info('build', 'Rearranging server assets...'); opts.logger.info('build', 'Rearranging server assets...');
const serverRoot = const serverRoot =
opts.settings.buildOutput === 'static' opts.settings.buildOutput === 'static'
? opts.settings.config.build.client ? opts.settings.config.build.client
: opts.settings.config.build.server; : opts.settings.config.build.server;
const clientRoot = opts.settings.config.build.client; const clientRoot = opts.settings.config.build.client;
const assets = opts.settings.config.build.assets; if (ssrOutputAssetNames.length > 0) {
const serverAssets = new URL(`./${assets}/`, appendForwardSlash(serverRoot.toString())); await Promise.all(
const clientAssets = new URL(`./${assets}/`, appendForwardSlash(clientRoot.toString())); ssrOutputAssetNames.map(async function moveAsset(filename) {
const files = await glob(`**/*`, { const currentUrl = new URL(filename, appendForwardSlash(serverRoot.toString()));
cwd: fileURLToPath(serverAssets), const clientUrl = new URL(filename, appendForwardSlash(clientRoot.toString()));
}); const dir = new URL(path.parse(clientUrl.href).dir);
// It can't find this file because the user defines a custom path
if (files.length > 0) { // that includes the folder paths in `assetFileNames`
await Promise.all( if (!fs.existsSync(dir)) await fs.promises.mkdir(dir, { recursive: true });
files.map(async function moveAsset(filename) { return fs.promises.rename(currentUrl, clientUrl);
const currentUrl = new URL(filename, appendForwardSlash(serverAssets.toString())); }),
const clientUrl = new URL(filename, appendForwardSlash(clientAssets.toString())); );
const dir = new URL(path.parse(clientUrl.href).dir); removeEmptyDirs(fileURLToPath(serverRoot));
// It can't find this file because the user defines a custom path
// that includes the folder paths in `assetFileNames
if (!fs.existsSync(dir)) await fs.promises.mkdir(dir, { recursive: true });
return fs.promises.rename(currentUrl, clientUrl);
}),
);
removeEmptyDirs(fileURLToPath(serverAssets));
} }
} }

View file

@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
import { before, describe, it } from 'node:test'; import { before, describe, it } from 'node:test';
import { loadFixture } from './test-utils.js'; import { loadFixture } from './test-utils.js';
describe('custom the assets name function', () => { describe('custom assets name function', () => {
/** @type {import('./test-utils').Fixture} */ /** @type {import('./test-utils').Fixture} */
let fixture; let fixture;
@ -14,9 +14,15 @@ describe('custom the assets name function', () => {
await fixture.build(); await fixture.build();
}); });
it('It cant find this file cause the node throws an error if the users custom a path that includes the folder path', async () => { it('should load CSS file from custom client assets path', async () => {
const csslength = await fixture.readFile('client/assets/css/a.css'); const files = await fixture.readdir('/client/assets/css');
/** @type {Set<string>} */ const cssFile = files.find((file) => file === 'a.css');
assert.equal(!!csslength, true); assert.ok(cssFile, 'Expected CSS file to exist at client/assets/css/a.css');
});
it('should load image file from custom client assets path', async () => {
const files = await fixture.readdir('/client/imgAssets');
const imgFile = files.find((file) => file === 'penguin1.jpg');
assert.ok(imgFile, 'Expected image file to exist at client/imgAssets/penguin1.jpg');
}); });
}); });

View file

@ -18,14 +18,14 @@ export default defineConfig({
const { ext, dir, base } = path.parse(option.name); const { ext, dir, base } = path.parse(option.name);
if (ext == ".css") return path.join(dir, "assets/css", 'a.css'); if (ext == ".css") return path.join(dir, "assets/css", 'a.css');
return "assets/img/[name].[ext]"; return "imgAssets/[name].[ext]";
} }
} }
} }
} }
}, },
build: { build: {
assets: 'assets' assets: 'assetsDir'
}, },
output: "server", output: "server",
adapter: node({ adapter: node({

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,5 +1,6 @@
--- ---
const title = 'My App'; const title = 'My App';
import p1Url from '../images/penguin1.jpg';
--- ---
<html> <html>
@ -8,6 +9,7 @@ const title = 'My App';
</head> </head>
<body> <body>
<h1>{title}</h1> <h1>{title}</h1>
<img src={p1Url.src}/>
</body> </body>
</html> </html>