From 0411b2ccb87e634cebb0274f18cb3a4cf73bcfe5 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Thu, 20 Jul 2023 15:28:31 +0900 Subject: [PATCH] feat: support JIT compilation opt-outing (#2250) * feat: support JIT compilation opt-outing * fix * updates * update snapshot --- docs/content/3.options/6.misc.md | 12 +++++++++++- playground/nuxt.config.ts | 1 + src/bundler.ts | 12 +++++++----- src/constants.ts | 1 + src/module.ts | 10 +++++++++- src/nitro.ts | 5 +++-- src/types.ts | 1 + test/__snapshots__/gen.test.ts.snap | 6 +++--- 8 files changed, 36 insertions(+), 12 deletions(-) diff --git a/docs/content/3.options/6.misc.md b/docs/content/3.options/6.misc.md index 68ffc7314..fef0b5433 100644 --- a/docs/content/3.options/6.misc.md +++ b/docs/content/3.options/6.misc.md @@ -25,12 +25,22 @@ Supported properties: ## `compilation` - type: `object` -- default: `{ strictMessage: true, escapeHtml: false }` +- default: `{ jit: true, strictMessage: true, escapeHtml: false }` Configure flags that sets the behavior compilation of locale messages. Supported properties: +- `jit` (default: `true`) Whether to use the JIT compilation of Vue I18n message compiler. + + ::alert{type="warning"} + + Mean that necessary to pre-compile locale messages that are not managed by the nuxt i18n module (e.g. in the case of importing from a specific URL, you will need to precompile them yourself.) + + And also, you need to understand that you cannot support use cases where you dynamically compose locale messages from the back-end via an API. + + :: + - `strictMessage` (default: `true`) Strictly check that the locale message does not contain HTML tags. If HTML tags are included, an error is thrown. ::alert{type="warning"} diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 5b16a8734..4ead424f0 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -111,6 +111,7 @@ export default defineNuxtConfig({ jsTsFormatResource: true }, compilation: { + // jit: false, strictMessage: false, escapeHtml: true }, diff --git a/src/bundler.ts b/src/bundler.ts index 9131f097b..65029d4e0 100644 --- a/src/bundler.ts +++ b/src/bundler.ts @@ -70,7 +70,7 @@ export async function extendBundler( const webpackPluginOptions: PluginOptions = { runtimeOnly: true, allowDynamic: true, - jitCompilation: true, + jitCompilation: nuxtOptions.compilation.jit, strictMessage: nuxtOptions.compilation.strictMessage, escapeHtml: nuxtOptions.compilation.escapeHtml } @@ -87,7 +87,9 @@ export async function extendBundler( extendWebpackConfig(config => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- `config.plugins` is safe, so it's assigned with nuxt! config.plugins!.push( - new webpack.DefinePlugin(assign(getFeatureFlags(), { __DEBUG__: String(nuxtOptions.debug) })) + new webpack.DefinePlugin( + assign(getFeatureFlags(nuxtOptions.compilation.jit), { __DEBUG__: String(nuxtOptions.debug) }) + ) ) }) } catch (e: unknown) { @@ -101,7 +103,7 @@ export async function extendBundler( const vitePluginOptions: PluginOptions = { runtimeOnly: true, allowDynamic: true, - jitCompilation: true, + jitCompilation: nuxtOptions.compilation.jit, strictMessage: nuxtOptions.compilation.strictMessage, escapeHtml: nuxtOptions.compilation.escapeHtml } @@ -126,11 +128,11 @@ export async function extendBundler( }) } -export function getFeatureFlags() { +export function getFeatureFlags(jit = true) { return { __VUE_I18N_FULL_INSTALL__: 'true', __VUE_I18N_LEGACY_API__: 'true', __INTLIFY_PROD_DEVTOOLS__: 'false', - __INTLIFY_JIT_COMPILATION__: 'true' + __INTLIFY_JIT_COMPILATION__: String(jit) } } diff --git a/src/constants.ts b/src/constants.ts index 07aff709e..d4ba10b46 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -36,6 +36,7 @@ export const DEFAULT_OPTIONS = { jsTsFormatResource: false }, compilation: { + jit: true, strictMessage: true, escapeHtml: false }, diff --git a/src/module.ts b/src/module.ts index 80ede6ee1..3b1f4e1b5 100644 --- a/src/module.ts +++ b/src/module.ts @@ -65,6 +65,14 @@ export default defineNuxtModule({ logger.warn('JS / TS extension format is experimental') } + if (!options.compilation.jit) { + logger.warn( + 'Opt-out JIT compilation. ' + + `It's necessary to pre-compile locale messages that are not managed by the nuxt i18n module (e.g. in the case of importing from a specific URL, you will need to precompile them yourself.) ` + + `And also, you need to understand that you cannot support use cases where you dynamically compose locale messages from the back-end via an API.` + ) + } + /** * Check vertions */ @@ -289,7 +297,7 @@ export default defineNuxtModule({ * setup nitro */ - await setupNitro(nuxt) + await setupNitro(nuxt, options) /** * auto imports diff --git a/src/nitro.ts b/src/nitro.ts index 6497b0176..95eb0a69f 100644 --- a/src/nitro.ts +++ b/src/nitro.ts @@ -1,9 +1,10 @@ import { assign } from '@intlify/shared' import { getFeatureFlags } from './bundler' +import type { NuxtI18nOptions } from './types' import type { Nuxt } from '@nuxt/schema' -export async function setupNitro(nuxt: Nuxt) { +export async function setupNitro(nuxt: Nuxt, nuxtOptions: Required) { if (nuxt.options.ssr) { if (!nuxt.options.nitro) { nuxt.options.nitro = {} @@ -11,6 +12,6 @@ export async function setupNitro(nuxt: Nuxt) { const nitroConfig = nuxt.options.nitro // vue-i18n feature flags configuration for server-side (server api, server middleware, etc...) - nitroConfig.replace = assign(nitroConfig.replace || {}, getFeatureFlags()) + nitroConfig.replace = assign(nitroConfig.replace || {}, getFeatureFlags(nuxtOptions.compilation.jit)) } } diff --git a/src/types.ts b/src/types.ts index e66c1698e..b580dd19b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -60,6 +60,7 @@ export interface ExperimentalFeatures { } export interface LocaleMessageCompilationOptions { + jit?: boolean strictMessage?: boolean escapeHtml?: boolean } diff --git a/test/__snapshots__/gen.test.ts.snap b/test/__snapshots__/gen.test.ts.snap index d29853372..051329a83 100644 --- a/test/__snapshots__/gen.test.ts.snap +++ b/test/__snapshots__/gen.test.ts.snap @@ -20,7 +20,7 @@ export const resolveNuxtI18nOptions = async (context) => { return nuxtI18nOptions } -export const nuxtI18nOptionsDefault = Object({experimental: Object({\\"jsTsFormatResource\\":false}),compilation: Object({\\"strictMessage\\":true,\\"escapeHtml\\":false}),vueI18n: \\"\\",locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: \\"composition\\",debug: false}) +export const nuxtI18nOptionsDefault = Object({experimental: Object({\\"jsTsFormatResource\\":false}),compilation: Object({\\"jit\\":true,\\"strictMessage\\":true,\\"escapeHtml\\":false}),vueI18n: \\"\\",locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: \\"composition\\",debug: false}) export const nuxtI18nInternalOptions = Object({__normalizedLocales: [Object({\\"code\\":\\"en\\"})]}) export const NUXT_I18N_MODULE_ID = \\"@nuxtjs/i18n\\" @@ -117,7 +117,7 @@ export const resolveNuxtI18nOptions = async (context) => { return nuxtI18nOptions } -export const nuxtI18nOptionsDefault = Object({experimental: Object({\\"jsTsFormatResource\\":false}),compilation: Object({\\"strictMessage\\":true,\\"escapeHtml\\":false}),vueI18n: \\"\\",locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: \\"composition\\",debug: false}) +export const nuxtI18nOptionsDefault = Object({experimental: Object({\\"jsTsFormatResource\\":false}),compilation: Object({\\"jit\\":true,\\"strictMessage\\":true,\\"escapeHtml\\":false}),vueI18n: \\"\\",locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: \\"composition\\",debug: false}) export const nuxtI18nInternalOptions = Object({__normalizedLocales: [Object({\\"code\\":\\"en\\"})]}) export const NUXT_I18N_MODULE_ID = \\"@nuxtjs/i18n\\" @@ -143,7 +143,7 @@ export const resolveNuxtI18nOptions = async (context) => { return nuxtI18nOptions } -export const nuxtI18nOptionsDefault = Object({experimental: Object({\\"jsTsFormatResource\\":false}),compilation: Object({\\"strictMessage\\":true,\\"escapeHtml\\":false}),vueI18n: \\"\\",locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: \\"composition\\",debug: false}) +export const nuxtI18nOptionsDefault = Object({experimental: Object({\\"jsTsFormatResource\\":false}),compilation: Object({\\"jit\\":true,\\"strictMessage\\":true,\\"escapeHtml\\":false}),vueI18n: \\"\\",locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: \\"composition\\",debug: false}) export const nuxtI18nInternalOptions = Object({__normalizedLocales: [Object({\\"code\\":\\"en\\"})]}) export const NUXT_I18N_MODULE_ID = \\"@nuxtjs/i18n\\"