Skip to content

Commit 8b77ee3

Browse files
authored
feat!: default enable for JIT compilation (#1852)
1 parent 51a009d commit 8b77ee3

35 files changed

+81
-197
lines changed

docs/guide/advanced/optimization.md

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,33 @@
33

44
## Performance
55

6-
As described in "[installation](../installation##from-cdn-or-without-a-bundler)" section, Vue I18n offer the following two built ES modules for Bundler.
6+
As described in "[Different Distribution files](../extra/dist##from-cdn-or-without-a-bundler)" section, Vue I18n offer the following two built ES modules for Bundler.
77

88
- message compiler + runtime: **`vue-i18n.esm-bundler.js`**
99
- runtime only: **`vue-i18n.runtime.esm-bundler.js`**
1010

11-
For bundler, it’s configured to bundle `vue-i18n.esm-bundler.js` with [`@intlify/bundle-tools`](https://github.com/intlify/bundle-tools#intlifybundle-tools) as default. If you want to reduce the bundle size further, you can configure the bundler to use `vue-i18n.runtime.esm-bundler.js`, which is runtime only.
11+
For bundler, it’s configured to bundle `vue-i18n.esm-bundler.js` with [`@intlify/unplugin-vue-i18n`](https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n) as default. If you want to reduce the bundle size further, you can configure the bundler to use `vue-i18n.runtime.esm-bundler.js`, which is runtime only.
1212

13-
:::danger NOTE
14-
IF [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is enabled, `vue-i18n.esm-bundler.js` would not work with compiler due to `eval` statements. These statements violate the `default-src 'self'` header. Instead you need to use `vue-i18n.runtime.esm-bundler.js`.
15-
:::
13+
The use of ES Module `vue-i18n.runtime.esm-bundler.js` means that **all locale messages have to pre-compile to Message functions or AST resources**. what this means it improves performance because vue-i18n just only execute Message functions, so no compilation.
1614

17-
:::warning NOTICE
18-
From v9.3, the CSP issue can be worked around by JIT compilation of the vue-i18n message compiler. See [JIT compilation for details](#jit-compilation).
15+
:::tip NOTE
16+
Before v9.3, the locale messages will be compiled to Message functions, after v9.3 or later these will be compiled to AST with `@intlify/bundle-tools`.
1917
:::
2018

21-
The use of this ES Module means that **all locale messages have to pre-compile to Message functions**. what this means it improves performance because vue-i18n just only execute Message functions, so no compilation.
22-
23-
Also, the message compiler is not bundled, therefore **bundle size can be reduced**
19+
:::tip NOTE
20+
Before v9.3, all locale messages are compiled with `@intlify/unplugin-vue-i18n`, so the message compiler is not bundled, **bundle size can be reduced**.
2421

25-
:::warning NOTICE
26-
If you are using the JIT compilation, all locale messages will not necessarily be compiled with the Message function.
22+
After v9.3, since the message compiler is also bundled, the bundle size cannot be reduced. **This is a trade-off**.
23+
About the reason, See [JIT compilation for details](#jit-compilation).
24+
:::
2725

28-
Also, since the message compiler is also bundled, the bundle size cannot be reduced. **This is a trade-off**.
26+
:::danger NOTE
27+
If [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is enabled in before v9.3, `vue-i18n.esm-bundler.js` would not work with compiler due to `eval` statements. These statements violate the `default-src 'self'` header. Instead you need to use `vue-i18n.runtime.esm-bundler.js`.
2928
:::
3029

30+
:::warning NOTICE
31+
From v9.3, the CSP issue can be worked around by JIT compilation of the vue-i18n message compiler. See [JIT compilation for details](#jit-compilation).
32+
:::
3133

3234
## How to configure
3335

@@ -132,14 +134,14 @@ About how to configure for bundler, see the [here](#configure-feature-flags-for-
132134
:new: 9.3+
133135
:::
134136
135-
Before v9.3, vue-i18n message compiler precompiled locale messages like AOT.
137+
Before v9.3, vue-i18n message compiler precompiled locale messages like AOT (Ahead Of Time).
136138
137139
However, it had the following issues:
138140
139141
- CSP issues: hard to work on service/web workers, edge-side runtimes of CDNs and etc.
140142
- Back-end integration: hard to get messages from back-end such as database via API and localize them dynamically
141143
142-
To solve these issues, JIT style compilation is supported message compiler.
144+
To solve these issues, JIT (Just In Time) style compilation is supported message compiler.
143145
144146
Each time localization is performed in an application using `$t` or `t` functions, message resources will be compiled on message compiler.
145147
@@ -152,6 +154,10 @@ You need to configure the following feature flag with `esm-bundler` build and bu
152154
This feature is opted out as default, because compatibility with previous version before v9.3.
153155
:::
154156
157+
:::warning NOTICE
158+
From v10, JIT compilation is enabled by default, so it is no longer necessary to set the `__INTLIFY_JIT_COMPILATION__` flag in the bundler.
159+
:::
160+
155161
About how to configure for bundler, see the [here](#configure-feature-flags-for-bundler).
156162
157163

docs/guide/migration/breaking10.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@
44
Vue I18n v10 **is still an alpha version**.
55
:::
66

7+
## Default enable for JIT compilation
8+
9+
**Reason**: CSP problems can be solved and dynamic resources can be supported
10+
11+
JIT compilation was introduced in v9.3. It was not enabled by default.
12+
13+
Nuxt I18n, which integrates vue-i18n, already has this feature enabled and stable by default.
14+
https://i18n.nuxtjs.org/docs/options/compilation#jit
15+
16+
To use this feature in Vue I18n, we had to use bundler and `@intlify/unplugin-vue-i18n` to enable the `__INTLIFY_JIT_COMPILATION__` flag.
17+
By default in the JIT compilation, this flag is no longer needed starting with v10.
18+
19+
If you would not still using the JIT compilation and would be moving up to v10 or later, **you will need to rebuild your application once**.
20+
21+
About JIT compilation details, See "[Optimazation](../advanced/optimization.md)".
22+
723
## Change `$t` and `t` overloaded signature for Legacy API mode
824

925
In Vue I18n v9, it has a different interface from the Composition API mode and Legacy API mode of `$t` and `t` overloaded signature.

packages/core-base/src/compilation.ts

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
detectHtmlTag
66
} from '@intlify/message-compiler'
77
import { format as formatMessage } from './format'
8-
import { CoreErrorCodes, createCoreError } from './errors'
98

109
import type {
1110
CompileOptions,
@@ -53,53 +52,6 @@ function baseCompile(
5352
}
5453

5554
/* #__NO_SIDE_EFFECTS__ */
56-
export const compileToFunction = <
57-
Message = string,
58-
MessageSource = string | ResourceNode
59-
>(
60-
message: MessageSource,
61-
context: MessageCompilerContext
62-
): MessageFunction<Message> => {
63-
if (!isString(message)) {
64-
throw createCoreError(CoreErrorCodes.NOT_SUPPORT_NON_STRING_MESSAGE)
65-
}
66-
67-
if (__RUNTIME__) {
68-
__DEV__ &&
69-
warn(
70-
`Runtime compilation is not supported in ${
71-
__BUNDLE_FILENAME__ || 'N/A'
72-
}.`
73-
)
74-
return (() => message) as MessageFunction<Message>
75-
} else {
76-
// check HTML message
77-
const warnHtmlMessage = isBoolean(context.warnHtmlMessage)
78-
? context.warnHtmlMessage
79-
: true
80-
__DEV__ && checkHtmlMessage(message, warnHtmlMessage)
81-
82-
// check caches
83-
const onCacheKey = context.onCacheKey || defaultOnCacheKey
84-
const cacheKey = onCacheKey(message)
85-
const cached = (compileCache as MessageFunctions<Message>)[cacheKey]
86-
if (cached) {
87-
return cached
88-
}
89-
90-
// compile
91-
const { code, detectError } = baseCompile(message, context)
92-
93-
// evaluate function
94-
const msg = new Function(`return ${code}`)() as MessageFunction<Message>
95-
96-
// if occurred compile error, don't cache
97-
return !detectError
98-
? ((compileCache as MessageFunctions<Message>)[cacheKey] = msg)
99-
: msg
100-
}
101-
}
102-
10355
export function compile<
10456
Message = string,
10557
MessageSource = string | ResourceNode
@@ -111,7 +63,7 @@ export function compile<
11163
(__ESM_BROWSER__ ||
11264
__NODE_JS__ ||
11365
__GLOBAL__ ||
114-
(__FEATURE_JIT_COMPILATION__ && !__FEATURE_DROP_MESSAGE_COMPILER__)) &&
66+
!__FEATURE_DROP_MESSAGE_COMPILER__) &&
11567
isString(message)
11668
) {
11769
// check HTML message

packages/core-base/src/misc.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ export function initFeatureFlags(): void {
99
getGlobalThis().__INTLIFY_PROD_DEVTOOLS__ = false
1010
}
1111

12-
if (typeof __FEATURE_JIT_COMPILATION__ !== 'boolean') {
13-
getGlobalThis().__INTLIFY_JIT_COMPILATION__ = false
14-
}
15-
1612
if (typeof __FEATURE_DROP_MESSAGE_COMPILER__ !== 'boolean') {
1713
getGlobalThis().__INTLIFY_DROP_MESSAGE_COMPILER__ = false
1814
}

packages/core-base/test/compilation.test.ts

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,7 @@ vi.mock('@intlify/shared', async () => {
99
})
1010

1111
import { baseCompile } from '@intlify/message-compiler'
12-
import {
13-
compileToFunction,
14-
compile,
15-
isMessageAST,
16-
clearCompileCache
17-
} from '../src/compilation'
12+
import { compile, isMessageAST, clearCompileCache } from '../src/compilation'
1813
import { createMessageContext as context } from '../src/runtime'
1914

2015
const DEFAULT_CONTEXT = { locale: 'en', key: 'key' }
@@ -43,25 +38,6 @@ describe('isMessageAST', () => {
4338
})
4439
})
4540

46-
describe('compileToFunction', () => {
47-
test('basic', () => {
48-
const msg = compileToFunction('hello {name}!', DEFAULT_CONTEXT)
49-
const ctx = context({
50-
named: { name: 'kazupon' }
51-
})
52-
expect(msg(ctx)).toBe('hello kazupon!')
53-
})
54-
55-
test('error', () => {
56-
let occured = false
57-
compileToFunction('hello {name!', {
58-
...DEFAULT_CONTEXT,
59-
onError: () => (occured = true)
60-
})
61-
expect(occured).toBe(true)
62-
})
63-
})
64-
6541
describe('compile', () => {
6642
test('basic', () => {
6743
const msg = compile('hello {name}!', DEFAULT_CONTEXT)

packages/core-base/test/datetime.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
registerMessageCompiler,
2828
registerLocaleFallbacker
2929
} from '../src/context'
30-
import { compileToFunction } from '../src/compilation'
30+
import { compile } from '../src/compilation'
3131
import { fallbackWithLocaleChain } from '../src/fallbacker'
3232

3333
import type { DateTimeFormats } from '../src/types'
@@ -86,7 +86,7 @@ const dts = [
8686
]
8787

8888
beforeEach(() => {
89-
registerMessageCompiler(compileToFunction)
89+
registerMessageCompiler(compile)
9090
registerLocaleFallbacker(fallbackWithLocaleChain)
9191
})
9292

packages/core-base/test/devtools.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createEmitter } from '@intlify/shared'
22
import { createCoreContext, translate } from '../src/index'
3-
import { compileToFunction } from '../src/compilation'
3+
import { compile } from '../src/compilation'
44
import { setDevToolsHook, getDevToolsHook } from '../src/devtools'
55

66
import type {
@@ -51,7 +51,7 @@ describe('translateDevTools', () => {
5151
const HELLO = 'Hello {name}!'
5252
const ctx = createCoreContext({
5353
locale: 'en',
54-
messageCompiler: compileToFunction,
54+
messageCompiler: compile,
5555
messages: {
5656
en: {
5757
hello: HELLO
@@ -78,7 +78,7 @@ describe('translateDevTools', () => {
7878
const ctx = createCoreContext({
7979
locale: 'en',
8080
fallbackLocale: ['ja'],
81-
messageCompiler: compileToFunction,
81+
messageCompiler: compile,
8282
messages: {
8383
ja: {
8484
hello: HELLO

packages/core-base/test/number.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
registerMessageCompiler,
2828
registerLocaleFallbacker
2929
} from '../src/context'
30-
import { compileToFunction } from '../src/compilation'
30+
import { compile } from '../src/compilation'
3131
import { fallbackWithLocaleChain } from '../src/fallbacker'
3232
import { NumberFormats } from '../src/types/index'
3333

@@ -69,7 +69,7 @@ const numberFormats: NumberFormats<MyNumberSchema, 'en-US' | 'ja-JP'> = {
6969
}
7070

7171
beforeEach(() => {
72-
registerMessageCompiler(compileToFunction)
72+
registerMessageCompiler(compile)
7373
registerLocaleFallbacker(fallbackWithLocaleChain)
7474
})
7575

packages/core-base/test/translate.test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
registerMessageResolver,
2121
registerLocaleFallbacker
2222
} from '../src/context'
23-
import { compileToFunction, compile } from '../src/compilation'
23+
import { compile } from '../src/compilation'
2424
import { fallbackWithLocaleChain } from '../src/fallbacker'
2525
import { resolveValue } from '../src/resolver'
2626
import { createTextNode } from './helper'
@@ -31,7 +31,7 @@ import type { MessageType, MessageProcessor } from '../src/runtime'
3131
import type { PickupKeys } from '../src/types/utils'
3232

3333
beforeEach(() => {
34-
registerMessageCompiler(compileToFunction)
34+
registerMessageCompiler(compile)
3535
registerMessageResolver(resolveValue)
3636
registerLocaleFallbacker(fallbackWithLocaleChain)
3737
})
@@ -978,8 +978,6 @@ describe('processor', () => {
978978

979979
describe('AST passing', () => {
980980
test('simple text', () => {
981-
registerMessageCompiler(compile)
982-
983981
const msg = 'hi kazupon !'
984982
const { ast } = baseCompile(msg, { jit: true, location: false })
985983

packages/core/src/index.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,19 @@
11
import {
22
registerMessageCompiler,
3-
compileToFunction,
43
compile,
54
registerMessageResolver,
65
resolveValue,
76
registerLocaleFallbacker,
87
fallbackWithLocaleChain
98
} from '@intlify/core-base'
109
import { initFeatureFlags } from '../../core-base/src/misc'
11-
import { getGlobalThis } from '@intlify/shared'
1210

1311
if (__ESM_BUNDLER__ && !__TEST__) {
1412
initFeatureFlags()
15-
if (__NODE_JS__) {
16-
// avoid Node.js CSP for Function()
17-
getGlobalThis().__INTLIFY_JIT_COMPILATION__ = true
18-
}
1913
}
2014

2115
// register message compiler at @intlify/core
22-
if (
23-
__ESM_BROWSER__ ||
24-
__NODE_JS__ ||
25-
__GLOBAL__ ||
26-
__FEATURE_JIT_COMPILATION__
27-
) {
28-
registerMessageCompiler(compile)
29-
} else {
30-
registerMessageCompiler(compileToFunction)
31-
}
16+
registerMessageCompiler(compile)
3217

3318
// register message resolver at @intlify/core
3419
registerMessageResolver(resolveValue)

0 commit comments

Comments
 (0)