Skip to content

Commit cf9ec7a

Browse files
authored
solve PRO-9899 by not using hash URLs in the first place, we already have release IDs in the URLs (#5624)
1 parent bcc5d37 commit cf9ec7a

6 files changed

Lines changed: 56 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@apostrophecms/vite": minor
3+
---
4+
5+
Assets from a module's `public/` folder that are referenced from CSS, such as web fonts loaded with `url('/modules/...')`, are now emitted at their original path instead of a content-hashed copy under `assets/`. As a result, `apos.asset.url('/modules/...')` in a template now matches the URL requested by the built CSS, so `<link rel="preload">` tags for web fonts work as intended rather than downloading each font twice. Cache busting is still provided by the release directory. Note that Vite still inlines assets smaller than 4 KB into the CSS, so such small fonts should not be preloaded. Also fixes the `assetsDir` build option, which was misspelled and silently ignored.

‎packages/vite/lib/vite-base-config.js‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,30 @@ module.exports = ({
3535
manifest: manifestRelPath,
3636
sourcemap: sourceMaps,
3737
emptyOutDir: false,
38-
assetDir: 'assets',
38+
assetsDir: 'assets',
3939
rollupOptions: {
4040
output: {
41-
entryFileNames: '[name]-build.js'
41+
entryFileNames: '[name]-build.js',
42+
assetFileNames
4243
}
4344
}
4445
}
4546
};
4647

4748
return config;
4849
};
50+
51+
// Assets that come from a module's `public/` folder (e.g. fonts referenced
52+
// from CSS via `url('/modules/...')`) are emitted at their original path,
53+
// without a content hash. This way `apos.asset.url('/modules/...')` in a
54+
// template matches the URL the built CSS requests, e.g. for preloading.
55+
// Cache busting is already provided by the release directory, just like
56+
// for the unhashed `[name]-build.js` entry files.
57+
function assetFileNames({ names = [], originalFileNames = [] }) {
58+
const original = originalFileNames[0]?.replaceAll('\\', '/');
59+
const isCss = names.some((name) => name.endsWith('.css'));
60+
if (!isCss && original?.startsWith('modules/')) {
61+
return original;
62+
}
63+
return 'assets/[name]-[hash][extname]';
64+
}
Binary file not shown.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@font-face {
2+
font-family: "Page Sans";
3+
src: url("/modules/article-page/fonts/sans.woff2") format("woff2");
4+
}
5+
6+
@font-face {
7+
font-family: "Widget Sans";
8+
src: url("/modules/article-widget/fonts/sans.woff2") format("woff2");
9+
}
Binary file not shown.

‎packages/vite/test/vite.test.js‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,30 @@ describe('@apostrophecms/vite', function () {
687687
assert.ok(fs.existsSync(path.join(bundleDir, 'public-src-module-bundle.js')));
688688
assert.ok(fs.existsSync(path.join(bundleDir, 'tools-module-bundle.js')));
689689
});
690+
691+
it('should emit public module assets at the URL apos.asset.url() returns', async function () {
692+
const bundleDir = apos.asset.getBundleRootDir();
693+
const css = await fs.readFile(path.join(bundleDir, 'article-bundle.css'), 'utf8');
694+
const fonts = [
695+
// Same file name in two modules must not collide
696+
'/modules/article-page/fonts/sans.woff2',
697+
'/modules/article-widget/fonts/sans.woff2'
698+
];
699+
for (const font of fonts) {
700+
assert.ok(css.includes(`url(${apos.asset.url(font)})`), `CSS does not reference ${font}`);
701+
const built = await fs.readFile(path.join(bundleDir, font));
702+
const source = await fs.readFile(path.join(
703+
__dirname,
704+
'modules',
705+
font.replace(/^\/modules\/([^/]+)\//, '$1/public/')
706+
));
707+
assert.ok(built.equals(source), `unexpected content for ${font}`);
708+
}
709+
const hashed = fs.existsSync(path.join(bundleDir, 'assets'))
710+
? (await fs.readdir(path.join(bundleDir, 'assets'))).filter(f => f.endsWith('.woff2'))
711+
: [];
712+
assert.deepEqual(hashed, [], 'no hashed copies of fonts expected');
713+
});
690714
});
691715
});
692716

0 commit comments

Comments
 (0)