@inlang/paraglide-js
Version:
[](https://www.npmjs.com/package/@inlang/paraglide-js) [ • 6.93 kB
JavaScript
import fs from "node:fs";
/**
* Returns the code for the `runtime.js` module
*/
export function createRuntimeFile(args) {
const urlPatterns = args.compilerOptions.urlPatterns ?? [];
const routeStrategies = args.compilerOptions.routeStrategies ?? [];
let defaultUrlPatternUsed = false;
// add default urlPatterns for a good out of the box experience
if (args.compilerOptions.urlPatterns === undefined) {
defaultUrlPatternUsed = true;
urlPatterns.push({
pattern: `:protocol://:domain(.*)::port?/:path(.*)?`,
localized: [],
});
for (const locale of args.locales) {
if (locale === args.baseLocale) {
continue;
}
urlPatterns[0]?.localized.push([
locale,
`:protocol://:domain(.*)::port?/${locale}/:path(.*)?`,
]);
}
urlPatterns[0]?.localized.push([
args.baseLocale,
`:protocol://:domain(.*)::port?/:path(.*)?`,
]);
}
const strategiesUsedByRoutes = routeStrategies.flatMap((routeStrategy) => "strategy" in routeStrategy ? routeStrategy.strategy : []);
const allUsedStrategies = new Set([
...args.compilerOptions.strategy,
...strategiesUsedByRoutes,
]);
const needsUrlPatternPolyfill = !defaultUrlPatternUsed || routeStrategies.length > 0;
// verify that urlPatterns' locales are valid
for (const urlPattern of urlPatterns) {
for (const [locale] of urlPattern.localized) {
if (!args.locales.includes(locale)) {
throw new Error(`Invalid locale "${locale}" in urlPatterns. It must be one of the locales defined in the "locales" array.`);
}
}
}
const code = `
${needsUrlPatternPolyfill ? `import "@inlang/paraglide-js/urlpattern-polyfill";` : "/** @type {any} */\nconst URLPattern = {}"}
${injectCode("./variables.js")
.replace(`export const baseLocale = "en";`, `export const baseLocale = "${args.baseLocale}";`)
.replace(`export const locales = /** @type {readonly string[]} */ (["en", "de"]);`, `export const locales = /** @type {const} */ (${JSON.stringify(args.locales)});`)
.replace(`export const strategy = ["globalVariable"];`, `export const strategy = ${JSON.stringify(args.compilerOptions.strategy, null, 2)};`)
.replace(`<cookie-name>`, `${args.compilerOptions.cookieName}`)
.replace(`60 * 60 * 24 * 400`, `${args.compilerOptions.cookieMaxAge}`)
.replace(`<cookie-domain>`, `${args.compilerOptions.cookieDomain}`)
.replace(`export const routeStrategies = [];`, `export const routeStrategies = ${JSON.stringify(routeStrategies, null, 2)};`)
.replace(`export const TREE_SHAKE_COOKIE_STRATEGY_USED = false;`, `const TREE_SHAKE_COOKIE_STRATEGY_USED = ${allUsedStrategies.has("cookie")};`)
.replace(`export const TREE_SHAKE_URL_STRATEGY_USED = false;`, `const TREE_SHAKE_URL_STRATEGY_USED = ${allUsedStrategies.has("url")};`)
.replace(`export const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = false;`, `const TREE_SHAKE_GLOBAL_VARIABLE_STRATEGY_USED = ${allUsedStrategies.has("globalVariable")};`)
.replace(`export const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = false;`, `const TREE_SHAKE_PREFERRED_LANGUAGE_STRATEGY_USED = ${allUsedStrategies.has("preferredLanguage")};`)
.replace(`export const urlPatterns = [];`, `export const urlPatterns = ${JSON.stringify(urlPatterns, null, 2)};`)
.replace(`export const disableAsyncLocalStorage = false;`, `export const disableAsyncLocalStorage = ${args.compilerOptions.disableAsyncLocalStorage};`)
.replace(`export const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = false;`, `const TREE_SHAKE_DEFAULT_URL_PATTERN_USED = ${defaultUrlPatternUsed};`)
.replace(`export const experimentalMiddlewareLocaleSplitting = false;`, `export const experimentalMiddlewareLocaleSplitting = ${args.compilerOptions.experimentalMiddlewareLocaleSplitting};`)
.replace(`export const isServer = typeof window === "undefined";`, `export const isServer = ${args.compilerOptions.isServer};`)
.replace(`export const experimentalStaticLocale = undefined;`, args.compilerOptions.experimentalStaticLocale
? `export const experimentalStaticLocale = assertIsLocale(${args.compilerOptions.experimentalStaticLocale});`
: `export const experimentalStaticLocale = undefined;`)
.replace(`export const localStorageKey = "PARAGLIDE_LOCALE";`, `export const localStorageKey = "${args.compilerOptions.localStorageKey}";`)
.replace(`export const TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = false;`, `const TREE_SHAKE_LOCAL_STORAGE_STRATEGY_USED = ${allUsedStrategies.has("localStorage")};`)}
/** @type {any} */ (globalThis).__paraglide =
/** @type {any} */ (globalThis).__paraglide ?? {};
/** @type {any} */ (globalThis).__paraglide.ssr =
/** @type {any} */ (globalThis).__paraglide.ssr ?? {};
${injectCode("./get-locale.js")}
${injectCode("./get-text-direction.js")}
${injectCode("./set-locale.js")}
${injectCode("./get-url-origin.js")}
${injectCode("./check-locale.js")}
${injectCode("./extract-locale-from-request.js")}
${injectCode("./extract-locale-from-request-async.js")}
${injectCode("./extract-locale-from-cookie.js", {
privateExports: ["clearLocaleCookieCache"],
})}
${injectCode("./extract-locale-from-header.js")}
${injectCode("./extract-locale-from-navigator.js")}
${injectCode("./extract-locale-from-url.js")}
${injectCode("./localize-url.js")}
${injectCode("./should-redirect.js")}
${injectCode("./localize-href.js")}
${injectCode("./track-message-call.js")}
${injectCode("./generate-static-localized-urls.js")}
${injectCode("./strategy.js")}
${injectCode("./type-definitions.js").replace(`@typedef {string} Locale`, `@typedef {typeof locales[number]} Locale`)}
`;
return code;
}
/**
* Load a file from the current directory.
*
* Prunes the imports on top of the file as the runtime is
* self-contained.
*
* @param {string} path
* @param {{ privateExports?: string[] }} [options]
* @returns {string}
*/
function injectCode(path, options) {
const code = fs.readFileSync(new URL(path, import.meta.url), "utf-8");
// Regex to match single-line and multi-line imports
const importRegex = /import\s+[\s\S]*?from\s+['"][^'"]+['"]\s*;?/g;
const sourceMapRegex = /\/\/# sourceMappingURL=.*$/gm;
const blockSourceMapRegex = /\/\*# sourceMappingURL=.*?\*\//g;
let injected = code
.replace(importRegex, "")
.replace(sourceMapRegex, "")
.replace(blockSourceMapRegex, "")
.trim();
for (const exportName of options?.privateExports ?? []) {
injected = injected.replace(new RegExp(`\\bexport\\s+function\\s+${exportName}\\b`, "g"), `function ${exportName}`);
}
return injected;
}
//# sourceMappingURL=create-runtime.js.map