Skip to content

Commit

Permalink
fix(i18n): don't make virtual modules no-op
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico committed Apr 3, 2024
1 parent 8db630c commit d0ce475
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-points-hunt.md
@@ -0,0 +1,5 @@
---
"astro": patch
---

Fixes a case where the `i18n` virtual module was transformed into a no-op function when some functions were used inside a non-prerendered page.
4 changes: 4 additions & 0 deletions packages/astro/src/core/build/plugins/plugin-chunks.ts
Expand Up @@ -12,6 +12,10 @@ export function vitePluginChunks(): VitePlugin {
if (id.includes('astro/dist/runtime/server/')) {
return 'astro/server';
}
// Split the Astro runtime into a separate chunk for readability
if (id.includes('astro/dist/runtime')) {
return 'astro';
}
},
});
},
Expand Down
15 changes: 11 additions & 4 deletions packages/astro/src/core/build/plugins/plugin-prerender.ts
Expand Up @@ -5,6 +5,7 @@ import type { BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
import { extendManualChunks } from './util.js';
import { ASTRO_VIRTUAL_MODULE } from '../../constants.js';

function vitePluginPrerender(opts: StaticBuildOptions, internals: BuildInternals): VitePlugin {
return {
Expand All @@ -13,12 +14,9 @@ function vitePluginPrerender(opts: StaticBuildOptions, internals: BuildInternals
outputOptions(outputOptions) {
extendManualChunks(outputOptions, {
after(id, meta) {
// Split the Astro runtime into a separate chunk for readability
if (id.includes('astro/dist/runtime')) {
return 'astro';
}
const pageInfo = internals.pagesByViteID.get(id);
let hasSharedModules = false;
let hasAstroVirtualModules = false;
if (pageInfo) {
// prerendered pages should be split into their own chunk
// Important: this can't be in the `pages/` directory!
Expand All @@ -43,12 +41,20 @@ function vitePluginPrerender(opts: StaticBuildOptions, internals: BuildInternals
// Given the previous statement, we only check if
// - the module is a page, and it's not pre-rendered
// - the module is the middleware
// - the module belongs to our virtual modules, which belong to `
// If one of these conditions is met, we need a separate chunk
for (const importer of moduleMeta.importedIds) {
// we don't want to analyze the same module again, so we skip it
if (importer !== id) {
const importerModuleMeta = meta.getModuleInfo(importer);
if (importerModuleMeta) {
if (
importerModuleMeta.meta &&
importerModuleMeta.meta[ASTRO_VIRTUAL_MODULE]
) {
hasAstroVirtualModules = true;
break;
}
// if the module is inside the pages
if (importerModuleMeta.id.includes('/pages')) {
// we check if it's not pre-rendered
Expand All @@ -70,6 +76,7 @@ function vitePluginPrerender(opts: StaticBuildOptions, internals: BuildInternals

opts.allPages;
pageInfo.hasSharedModules = hasSharedModules;
pageInfo.hasAstroVirtualModule = hasAstroVirtualModules;
pageInfo.route.prerender = true;
return 'prerender';
}
Expand Down
5 changes: 4 additions & 1 deletion packages/astro/src/core/build/static-build.ts
Expand Up @@ -374,7 +374,10 @@ async function cleanStaticOutput(
) {
const allStaticFiles = new Set();
for (const pageData of eachPageData(internals)) {
if (pageData.route.prerender && !pageData.hasSharedModules) {
if (
pageData.route.prerender &&
!(pageData.hasSharedModules || pageData.hasAstroVirtualModule)
) {
const { moduleSpecifier } = pageData;
const pageBundleId = internals.pageToBundleMap.get(moduleSpecifier);
const entryBundleId = internals.entrySpecifierToBundleMap.get(moduleSpecifier);
Expand Down
4 changes: 4 additions & 0 deletions packages/astro/src/core/build/types.ts
Expand Up @@ -29,6 +29,10 @@ export interface PageBuildData {
hoistedScript: { type: 'inline' | 'external'; value: string } | undefined;
styles: Array<{ depth: number; order: number; sheet: StylesheetAsset }>;
hasSharedModules: boolean;
/**
* Whether the page is using astro virtual modules
*/
hasAstroVirtualModule: boolean;
}

export type AllPagesData = Record<ComponentPath, PageBuildData>;
Expand Down
18 changes: 18 additions & 0 deletions packages/astro/src/core/constants.ts
Expand Up @@ -71,3 +71,21 @@ export const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [

// The folder name where to find the middleware
export const MIDDLEWARE_PATH_SEGMENT_NAME = 'middleware';

/**
* This constant is used to mark internal astro virtual modules. Use this constant to attach it to the metadata of the virtual module, e.g.:
*
* ```js
* function resolveId(id) {
* if (id === virtualModuleId) {
* return {
* id,
* meta: {
* [ASTRO_VIRTUAL_MODULE]: true,
* },
* }
* }
* }
* ```
*/
export const ASTRO_VIRTUAL_MODULE = 'astro-virtual-module';
15 changes: 13 additions & 2 deletions packages/astro/src/i18n/vite-plugin-i18n.ts
Expand Up @@ -2,6 +2,7 @@ import type * as vite from 'vite';
import type { AstroConfig, AstroSettings } from '../@types/astro.js';
import { AstroError } from '../core/errors/errors.js';
import { AstroErrorData } from '../core/errors/index.js';
import { ASTRO_VIRTUAL_MODULE } from '../core/constants.js';

const virtualModuleId = 'astro:i18n';

Expand Down Expand Up @@ -44,10 +45,20 @@ export default function astroInternationalization({
},
};
},
resolveId(id) {
async resolveId(id) {
if (id === virtualModuleId) {
if (i18n === undefined) throw new AstroError(AstroErrorData.i18nNotEnabled);
return this.resolve('astro/virtual-modules/i18n.js');

const resolved = await this.resolve('astro/virtual-modules/i18n.js');
if (resolved) {
return {
id: resolved.id,
meta: {
[ASTRO_VIRTUAL_MODULE]: true,
},
};
}
return undefined;
}
},
};
Expand Down

0 comments on commit d0ce475

Please sign in to comment.