Skip to content

Commit

Permalink
emitTs
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelstroschein committed Jan 14, 2025
1 parent c640dfd commit 2e1aeec
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 42 deletions.
26 changes: 14 additions & 12 deletions inlang/packages/paraglide-js/src/compiler/compileProject.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,21 @@ test("emitPrettierIgnore", async () => {
});

describe.each([
// { outputStructure: "locale-modules", emitTs: false },
{ outputStructure: "locale-modules", emitTs: true },
// { outputStructure: "message-modules", emitTs: false },
// { outputStructure: "message-modules", emitTs: true },
// useTsImports must be true to test emitTs. Otherwise, rolldown can't resolve the imports
{ outputStructure: "locale-modules", emitTs: false, useTsImports: false },
{ outputStructure: "locale-modules", emitTs: true, useTsImports: true },
{ outputStructure: "message-modules", emitTs: false, useTsImports: false },
{ outputStructure: "message-modules", emitTs: true, useTsImports: true },
] satisfies Array<ParaglideCompilerOptions>)(
"options",
async (compilerOptions) => {
const output = await compileProject({ project, compilerOptions });
const importExt = compilerOptions.useTsImports ? "ts" : "js";
describe("tree-shaking", () => {
test("should tree-shake unused messages", async () => {
const code = await bundleCode(
output,
`import * as m from "./paraglide/messages.js"
`import * as m from "./paraglide/messages.${importExt}"
console.log(m.sad_penguin_bundle())`
);
Expand All @@ -115,7 +117,7 @@ describe.each([
test("should not treeshake messages that are used", async () => {
const code = await bundleCode(
output,
`import * as m from "./paraglide/messages.js"
`import * as m from "./paraglide/messages.${importExt}"
console.log(
m.sad_penguin_bundle(),
Expand Down Expand Up @@ -146,8 +148,8 @@ describe.each([
// The compiled output needs to be bundled into one file to be dynamically imported.
const code = await bundleCode(
output,
`export * as m from "./paraglide/messages.js"
export * as runtime from "./paraglide/runtime.js"`
`export * as m from "./paraglide/messages.${importExt}"
export * as runtime from "./paraglide/runtime.${importExt}"`
);

// test is a direct result of a bug
Expand Down Expand Up @@ -289,8 +291,8 @@ describe.each([
});
const code = await bundleCode(
output,
`export * as m from "./paraglide/messages.js"
export * as runtime from "./paraglide/runtime.js"`
`export * as m from "./paraglide/messages.${importExt}"
export * as runtime from "./paraglide/runtime.${importExt}"`
);
const { m, runtime } = await importCode(code);

Expand Down Expand Up @@ -358,8 +360,8 @@ describe.each([

const code = await bundleCode(
output,
`export * as m from "./paraglide/messages.js"
export * as runtime from "./paraglide/runtime.js"`
`export * as m from "./paraglide/messages.${importExt}"
export * as runtime from "./paraglide/runtime.${importExt}"`
);
const { m, runtime } = await importCode(code);

Expand Down
27 changes: 24 additions & 3 deletions inlang/packages/paraglide-js/src/compiler/compileProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,29 @@ import { generateMessageModules } from "./output-structure/message-modules.js";

export type ParaglideCompilerOptions = {
/**
* Whether to emit d.ts files.
* Whether to emit TypeScript files instead of JSDoc annotated JavaScript.
*
* @default false
*/
emitTs?: boolean;
/**
* Whether to import files as TypeScript in the emitted code.
*
* The option is useful in some setups where TypeScript is run
* directly on the emitted code such as node --strip-types.
* [Here](https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/#path-rewriting-for-relative-paths)
* is more information on path rewriting for relative paths.
*
* ! Only works in combination with `emitTs: true`.
*
* @example
* // false
* import { getLocale } from "./runtime.js";
*
* // true
* import { getLocale } from "./runtime.ts";
*/
useTsImports?: boolean;
/**
* Whether to emit a .prettierignore file.
*
Expand All @@ -35,6 +53,7 @@ export type ParaglideCompilerOptions = {
const defaultCompilerOptions = {
outputStructure: "message-modules",
emitTs: false,
useTsImports: false,
emitGitIgnore: true,
emitPrettierIgnore: true,
} as const satisfies ParaglideCompilerOptions;
Expand Down Expand Up @@ -80,7 +99,8 @@ export const compileProject = async (args: {
compiledBundles,
settings,
fallbackMap,
optionsWithDefaults.emitTs
optionsWithDefaults.emitTs,
optionsWithDefaults.useTsImports
);
Object.assign(output, regularOutput);
}
Expand All @@ -90,7 +110,8 @@ export const compileProject = async (args: {
compiledBundles,
settings,
fallbackMap,
optionsWithDefaults.emitTs
optionsWithDefaults.emitTs,
optionsWithDefaults.useTsImports
);
Object.assign(output, messageModuleOutput);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,15 @@ test("should emit per locale message files", () => {

const emitTs = false;

const output = generateLocaleModules(bundles, settings, fallbackMap, emitTs);
const useTsImports = false;

const output = generateLocaleModules(
bundles,
settings,
fallbackMap,
emitTs,
useTsImports
);

expect(output).toHaveProperty("messages.js");
expect(output).toHaveProperty("messages/en.js");
Expand Down Expand Up @@ -73,7 +81,15 @@ test("the files should include files for each locale, even if there are no messa

const emitTs = false;

const output = generateLocaleModules(bundles, settings, fallbackMap, emitTs);
const useTsImports = false;

const output = generateLocaleModules(
bundles,
settings,
fallbackMap,
emitTs,
useTsImports
);

expect(output).toHaveProperty("messages.js");
expect(output).toHaveProperty("messages/en.js");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,33 @@ export function generateLocaleModules(
compiledBundles: CompiledBundleWithMessages[],
settings: Pick<ProjectSettings, "locales" | "baseLocale">,
fallbackMap: Record<string, string | undefined>,
emitTs: boolean
emitTs: boolean,
useTsImports: boolean
): Record<string, string> {

const fileExt = emitTs ? ".ts" : ".js";
const fileExt = emitTs ? "ts" : "js";
const importExt = useTsImports ? "ts" : "js";

const indexFile = [
"/* eslint-disable */",
'import { getLocale } from "./runtime.js"',
`import { getLocale } from "./runtime.${importExt}"`,
settings.locales
.map(
(locale) =>
`import * as ${jsIdentifier(locale)} from "./messages/${locale}.js"`
`import * as ${jsIdentifier(locale)} from "./messages/${locale}.${importExt}"`
)
.join("\n"),
compiledBundles.map(({ bundle }) => bundle.code).join("\n"),
].join("\n");

const output: Record<string, string> = {
["runtime" + fileExt]: createRuntime(settings, emitTs),
["registry" + fileExt]: createRegistry(emitTs),
["messages" + fileExt]: indexFile,
["runtime." + fileExt]: createRuntime(settings, emitTs),
["registry." + fileExt]: createRegistry(emitTs),
["messages." + fileExt]: indexFile,
};

// generate message files
for (const locale of settings.locales) {
const filename = emitTs ? `messages/${locale}.ts` : `messages/${locale}.js`;
const filename = `messages/${locale}.${fileExt}`;
let file = `
/* eslint-disable */
/**
Expand All @@ -42,7 +43,7 @@ export function generateLocaleModules(
*! WARNING: Only import from this file if you want to manually
*! optimize your bundle. Else, import from the \`messages.js\` file.
*/
import * as registry from '../registry.js'`;
import * as registry from '../registry.${importExt}'`;

for (const compiledBundle of compiledBundles) {
const compiledMessage = compiledBundle.messages[locale];
Expand All @@ -51,7 +52,7 @@ import * as registry from '../registry.js'`;
const fallbackLocale = fallbackMap[locale];
if (fallbackLocale) {
// use the fall back locale e.g. render the message in English if the German message is missing
file += `\nexport { ${id} } from "./${fallbackLocale}.js"`;
file += `\nexport { ${id} } from "./${fallbackLocale}.${importExt}"`;
} else {
// no fallback exists, render the bundleId
file += `\nexport const ${id} = () => '${id}'`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@ test("should emit per locale message files", () => {

const emitTs = false;

const useTsImports = false;

const output = generateMessageModules(
resources,
settings,
fallbackMap,
emitTs
emitTs,
useTsImports
);

expect(output).not.toHaveProperty("messages/en.js");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,39 @@ export function generateMessageModules(
compiledBundles: CompiledBundleWithMessages[],
settings: Pick<ProjectSettings, "locales" | "baseLocale">,
fallbackMap: Record<string, string | undefined>,
emitTs: boolean
emitTs: boolean,
useTsImports: boolean
): Record<string, string> {
const fileExt = emitTs ? ".ts" : ".js";
const fileExt = emitTs ? "ts" : "js";
const importExt = useTsImports ? "ts" : "js";

const output: Record<string, string> = {
["runtime" + fileExt]: createRuntime(settings, emitTs),
["registry" + fileExt]: createRegistry(emitTs),
["runtime." + fileExt]: createRuntime(settings, emitTs),
["registry." + fileExt]: createRegistry(emitTs),
};

// messages index file
output["messages" + fileExt] = [
output["messages." + fileExt] = [
"/* eslint-disable */",
...compiledBundles.map(
({ bundle }) => `export * from './messages/${bundle.node.id}/index.js'`
({ bundle }) =>
`export * from './messages/${bundle.node.id}/index.${importExt}'`
),
].join("\n");

// Creates a per message index file
for (const compiledBundle of compiledBundles) {
const filename = `messages/${compiledBundle.bundle.node.id}/index.js`;
const filename = `messages/${compiledBundle.bundle.node.id}/index.${fileExt}`;
const code = [
"/* eslint-disable */",
"import * as registry from '../../registry.js'",
`import * as registry from '../../registry.${importExt}'`,
settings.locales
.map(
(locale) =>
`import * as ${jsIdentifier(locale)} from "./${locale}.js"`
`import * as ${jsIdentifier(locale)} from "./${locale}.${importExt}"`
)
.join("\n"),
"import { getLocale } from '../../runtime.js'",
`import { getLocale } from '../../runtime.${importExt}'`,
"",
compiledBundle.bundle.code,
].join("\n");
Expand All @@ -49,7 +52,7 @@ export function generateMessageModules(
for (const compiledBundle of compiledBundles) {
let file = [
"/* eslint-disable */",
"import * as registry from '../../registry.js' ",
`import * as registry from '../../registry.${importExt}'`,
].join("\n");

const compiledMessage = compiledBundle.messages[locale];
Expand All @@ -59,7 +62,7 @@ export function generateMessageModules(
const fallbackLocale = fallbackMap[locale];
if (fallbackLocale) {
// take the fallback locale
file += `\nexport { ${id} } from "./${fallbackLocale}.js"`;
file += `\nexport { ${id} } from "./${fallbackLocale}.${importExt}"`;
} else {
// fallback to just the bundle id
file += `\nexport const ${id} = () => '${escapeForSingleQuoteString(
Expand All @@ -70,7 +73,8 @@ export function generateMessageModules(
file += `\n${compiledMessage.code}`;
}

output[`messages/${compiledBundle.bundle.node.id}/${locale}.js`] = file;
output[`messages/${compiledBundle.bundle.node.id}/${locale}.${fileExt}`] =
file;
}
}
return output;
Expand Down

0 comments on commit 2e1aeec

Please sign in to comment.