next-intlayer
Version:
Simplify internationalization i18n in Next.js with context providers, hooks, locale detection, and multilingual content integration.
185 lines • 5.97 kB
JavaScript
import { prepareIntlayer, runOnce } from "@intlayer/chokidar";
import {
ESMxCJSRequire,
getAppLogger,
getConfiguration,
normalizePath
} from "@intlayer/config";
import { IntlayerPlugin } from "@intlayer/webpack";
import merge from "deepmerge";
import fg from "fast-glob";
import { join, relative, resolve } from "path";
import { compareVersions } from "./compareVersion.mjs";
import { getNextVersion } from "./getNextVertion.mjs";
const isTurbopackEnabled = process.env.npm_lifecycle_script?.includes("--turbo");
const nextVersion = getNextVersion();
const isGteNext13 = compareVersions(nextVersion, "\u2265", "13.0.0");
const isGteNext15 = compareVersions(nextVersion, "\u2265", "15.0.0");
const isTurbopackStable = compareVersions(nextVersion, "\u2265", "15.3.0");
const getIsSwcPluginAvailable = () => {
try {
ESMxCJSRequire.resolve("@intlayer/swc");
return true;
} catch (e) {
return false;
}
};
const getPruneConfig = (intlayerConfig) => {
const { optimize, traversePattern, importMode } = intlayerConfig.build;
const { dictionariesDir, dynamicDictionariesDir, mainDir, baseDir } = intlayerConfig.content;
if (!optimize) return {};
if (!isGteNext13) return {};
const isSwcPluginAvailable = getIsSwcPluginAvailable();
if (!isSwcPluginAvailable) return {};
const logger = getAppLogger(intlayerConfig);
runOnce(
join(baseDir, ".next", "cache", "intlayer-prune-plugin-enabled.lock"),
() => logger("Intlayer prune plugin is enabled"),
1e3 * 10
// 10 seconds
);
const dictionariesEntryPath = join(mainDir, "dictionaries.mjs");
const dynamicDictionariesEntryPath = join(
mainDir,
"dynamic_dictionaries.mjs"
);
const filesListPattern = fg.sync(traversePattern, {
cwd: baseDir
}).map((file) => join(baseDir, file));
const filesList = [
...filesListPattern,
dictionariesEntryPath
// should add dictionariesEntryPath to replace it by a empty object if import made dynamic
];
return {
experimental: {
swcPlugins: [
[
ESMxCJSRequire.resolve("@intlayer/swc"),
{
dictionariesDir,
dictionariesEntryPath,
dynamicDictionariesDir,
dynamicDictionariesEntryPath,
importMode,
filesList,
replaceDictionaryEntry: false
}
]
]
}
};
};
const withIntlayer = async (nextConfig = {}) => {
if (typeof nextConfig !== "object") {
nextConfig = {};
}
const intlayerConfig = getConfiguration();
const sentinelPath = join(
intlayerConfig.content.baseDir,
".next",
"cache",
"intlayer-prepared.lock"
);
await runOnce(
sentinelPath,
async () => await prepareIntlayer(intlayerConfig)
);
const { mainDir, configDir, baseDir } = intlayerConfig.content;
const dictionariesPath = join(mainDir, "dictionaries.mjs");
const relativeDictionariesPath = relative(baseDir, dictionariesPath);
const unmergedDictionariesPath = join(mainDir, "unmerged_dictionaries.mjs");
const relativeUnmergedDictionariesPath = relative(
baseDir,
unmergedDictionariesPath
);
const configurationPath = join(configDir, "configuration.json");
const relativeConfigurationPath = relative(baseDir, configurationPath);
const turboConfig = {
resolveAlias: {
// prefix by './' to consider the path as relative to the project root. This is necessary for turbopack to work correctly.
// Normalize the path to avoid issues with the path separator on Windows
"@intlayer/dictionaries-entry": normalizePath(
`./${relativeDictionariesPath}`
),
"@intlayer/unmerged-dictionaries-entry": normalizePath(
`./${relativeUnmergedDictionariesPath}`
),
"@intlayer/config/built": normalizePath(`./${relativeConfigurationPath}`)
},
rules: {
"*.node": {
as: "*.node",
loaders: ["node-loader"]
}
}
};
const serverExternalPackages = [
"esbuild",
"module",
"fs",
"chokidar",
"fsevents"
];
const newConfig = {
// Only add `serverExternalPackages` if Next.js is v15+
...isGteNext15 ? {
// only for Next ≥15
serverExternalPackages
} : {
// only for Next ≥13 and <15.3
...isGteNext13 && {
serverComponentsExternalPackages: serverExternalPackages
}
},
...isTurbopackEnabled && {
...isGteNext15 && isTurbopackStable ? {
// only for Next ≥15.3
turbopack: turboConfig
} : {
experimental: {
// only for Next ≥13 and <15.3
turbo: turboConfig
}
}
},
webpack: (config, options) => {
if (typeof nextConfig.webpack === "function") {
config = nextConfig.webpack(config, options);
}
config.resolve.alias = {
...config.resolve.alias,
"@intlayer/dictionaries-entry": resolve(relativeDictionariesPath),
"@intlayer/unmerged-dictionaries-entry": resolve(
relativeUnmergedDictionariesPath
),
"@intlayer/config/built": resolve(relativeConfigurationPath)
};
config.externals.push({
esbuild: "esbuild",
module: "module",
fs: "fs",
chokidar: "chokidar",
fsevents: "fsevents"
});
config.module.rules.push({
test: /\.node$/,
loader: "node-loader"
});
const { isServer, nextRuntime } = options;
const isBuildCommand = process.env.npm_lifecycle_event === "build" || process.argv.some((arg) => arg === "build");
if (!isBuildCommand && isServer && nextRuntime === "nodejs") {
config.plugins.push(new IntlayerPlugin());
}
return config;
}
};
const pruneConfig = getPruneConfig(intlayerConfig);
const intlayerNextConfig = merge(pruneConfig, newConfig);
const result = merge(nextConfig, intlayerNextConfig);
return result;
};
export {
withIntlayer
};
//# sourceMappingURL=withIntlayer.mjs.map