Skip to content

Commit 6b4a118

Browse files
authored
improvement: vue-i18n re-packaging (#222)
* improvement: vue-i18n re-packaging * fix: rollup config
1 parent 0ad8896 commit 6b4a118

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+562
-9231
lines changed

benchmark/complex.js

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
const {
2-
baseCompile
3-
} = require('../packages/message-compiler/dist/message-compiler.cjs.prod.js')
4-
const {
5-
clearCompileCache
6-
} = require('../packages/runtime/dist/runtime.cjs.prod.js')
1+
const { baseCompile } = require('../packages/message-compiler')
72
const {
83
translate,
9-
createRuntimeContext
10-
} = require('../packages/core/dist/core.cjs.prod.js')
11-
const { createI18n } = require('../packages/vue-i18n/dist/vue-i18n.cjs.prod.js')
4+
createCoreContext,
5+
clearCompileCache
6+
} = require('../packages/core')
7+
const { createI18n } = require('../packages/vue-i18n')
128
const convertHrtime = require('convert-hrtime')
139

1410
const data = require('./complex.json')
@@ -27,7 +23,7 @@ console.log(`ms: ${end.milliseconds - start.milliseconds}`)
2723
console.log()
2824

2925
console.log(`resolve time with core: ${len} resources`)
30-
const ctx = createRuntimeContext({
26+
const ctx = createCoreContext({
3127
locale: 'en',
3228
modifiers: {
3329
caml: val => val

benchmark/simple.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
const {
2-
baseCompile
3-
} = require('../packages/message-compiler/dist/message-compiler.cjs.prod.js')
4-
const {
5-
clearCompileCache
6-
} = require('../packages/runtime/dist/runtime.cjs.prod.js')
1+
const { baseCompile } = require('../packages/message-compiler')
72
const {
83
translate,
9-
createRuntimeContext
10-
} = require('../packages/core/dist/core.cjs.prod.js')
11-
const { createI18n } = require('../packages/vue-i18n/dist/vue-i18n.cjs.prod.js')
4+
createCoreContext,
5+
clearCompileCache
6+
} = require('../packages/core')
7+
const { createI18n } = require('../packages/vue-i18n')
128
const convertHrtime = require('convert-hrtime')
139

1410
const simpleData = require('./simple.json')
@@ -28,7 +24,7 @@ console.log(`ms: ${end.milliseconds - start.milliseconds}`)
2824
console.log()
2925

3026
console.log(`resolve time with core: ${len} resources`)
31-
const ctx = createRuntimeContext({
27+
const ctx = createCoreContext({
3228
locale: 'en',
3329
messages: {
3430
en: simpleData
@@ -46,6 +42,7 @@ console.log()
4642

4743
console.log(`resolve time with composition: ${len} resources`)
4844
const i18n = createI18n({
45+
legacy: false,
4946
locale: 'en',
5047
messages: {
5148
en: simpleData

jest.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ module.exports = {
6666
__VERSION__: require('./package.json').version,
6767
__BROWSER__: false,
6868
__GLOBAL__: false,
69+
__RUNTIME__: false,
70+
__WARN_LABEL__: `'vue-i18n'`,
71+
__BUNDLE_FILENAME__: 'test.bundle.js',
6972
__ESM_BUNDLER__: true,
7073
__ESM_BROWSER__: false,
7174
__NODE_JS__: true,
@@ -93,6 +96,7 @@ module.exports = {
9396

9497
// A map from regular expressions to module names that allow to stub out resources with a single module
9598
moduleNameMapper: {
99+
'^@intlify/core/src/runtime$': '<rootDir>/packages/core/src/index.ts',
96100
'^@intlify/(.*?)$': '<rootDir>/packages/$1/src',
97101
'vue-i18n': '<rootDir>/packages/vue-i18n/src'
98102
},

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
"scripts": {
1212
"benchmark": "node ./benchmark/index.js",
1313
"build": "node scripts/build.js",
14+
"build:size": "npm-run-all --parallel build:size-*",
15+
"build:size-core": "rollup -c packages/size-check-core/rollup.config.js",
16+
"build:size-vue-i18n": "rollup -c packages/size-check-vue-i18n/rollup.config.js",
1417
"build:sourcemap": "yarn build --sourcemap",
1518
"build:type": "yarn build --types && tail -n +19 ./packages/vue-i18n/src/vue.d.ts >> ./packages/vue-i18n/dist/vue-i18n.d.ts",
1619
"clean": "npm-run-all --parallel clean:*",
@@ -19,7 +22,6 @@
1922
"clean:coverage": "rm -rf ./coverage",
2023
"clean:dist": "rm -rf ./dist/**",
2124
"clean:docs": "rm -rf ./docs/api/vue-i18n**.md",
22-
"clean:size": "rm -rf ./size-check/**/dist ./size-check/**/node_modules",
2325
"clean:type": "rm -rf ./types/** ./temp ./dist/vue-i18n.d.ts",
2426
"coverage": "opener coverage/lcov-report/index.html",
2527
"dev": "node scripts/dev.js",

packages/core/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,46 @@
22

33
The intlify core module for i18n
44

5+
## Which dist file to use?
6+
7+
### From CDN or without a Bundler
8+
9+
- **`core(.runtime).global(.prod).js`**:
10+
- For direct use via `<script src="...">` in the browser. Exposes the `IntlifyCore` global
11+
- Note that global builds are not [UMD](https://github.com/umdjs/umd) builds. They are built as [IIFEs](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) and is only meant for direct use via `<script src="...">`
12+
- In-browser locale messages compilation:
13+
- **`core.global.js`** is the "full" build that includes both the compiler and the runtime so it supports compiling locale messages on the fly
14+
- **`core.runtime.global.js`** contains only the runtime and requires locale messages to be pre-compiled during a build step
15+
- Inlines internal the bellow packages - i.e. it’s a single file with no dependencies on other files. This means you **must** import everything from this file and this file only to ensure you are getting the same instance of code
16+
- `@intlify/shared`
17+
- `@intlify/message-resolver`
18+
- `@intlify/message-compiler`
19+
- Contains hard-coded prod/dev branches, and the prod build is pre-minified. Use the `*.prod.js` files for production
20+
21+
- **`core(.runtime).esm-browser(.prod).js`**:
22+
- For usage via native ES modules imports (in browser via `<script type="module">`)
23+
- Shares the same runtime compilation, dependency inlining and hard-coded prod/dev behavior with the global build
24+
25+
### With a Bundler
26+
27+
- **`core(.runtime).esm-bundler.js`**:
28+
- For use with bundlers like `webpack`, `rollup` and `parcel`
29+
- Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler)
30+
- Does not ship minified builds (to be done together with the rest of the code after bundling)
31+
- Imports dependencies (e.g. `@intlify/message-compiler`, `@intlify/message-resolver`)
32+
- Imported dependencies are also `esm-bundler` builds and will in turn import their dependencies (e.g. `@intlify/message-compiler` imports `@intlify/shared`)
33+
- This means you **can** install/import these deps individually without ending up with different instances of these dependencies, but you must make sure they all resolve to the same version
34+
- In-browser locale messages compilation:
35+
- **`core.runtime.esm-bundler.js` (default)** is runtime only, and requires all locale messages to be pre-compiled. This is the default entry for bundlers (via `module` field in `package.json`) because when using a bundler templates are typically pre-compiled (e.g. in `*.json` files)
36+
- **`core.esm-bundler.js`**: includes the runtime compiler. Use this if you are using a bundler but still want locale messages compilation (e.g. templates via inline JavaScript strings)
37+
38+
### For Node.js (Server-Side)
39+
40+
- **`core.cjs(.prod).js`**:
41+
- For use in Node.js via `require()`
42+
- If you bundle your app with webpack with `target: 'node'` and properly externalize `@intlify/core`, this is the build that will be loaded
43+
- The dev/prod files are pre-built, but the appropriate file is automatically required based on `process.env.NODE_ENV`
44+
545
## :copyright: License
646

747
[MIT](http://opensource.org/licenses/MIT)

packages/core/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,12 @@
4646
"name": "IntlifyCore",
4747
"formats": [
4848
"esm-bundler",
49+
"esm-bundler-runtime",
4950
"esm-browser",
51+
"esm-browser-runtime",
5052
"cjs",
51-
"global"
53+
"global",
54+
"global-runtime"
5255
]
5356
},
5457
"sideEffects": false

packages/core/src/compile.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { warn, format, isBoolean } from '@intlify/shared'
2+
import { baseCompile, defaultOnError } from '@intlify/message-compiler'
3+
4+
import type { CompileOptions, CompileError } from '@intlify/message-compiler'
5+
import type { MessageFunction, MessageFunctions } from '@intlify/runtime'
6+
7+
const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/
8+
const WARN_MESSAGE = `Detected HTML in '{source}' message. Recommend not using HTML messages to avoid XSS.`
9+
10+
function checkHtmlMessage(source: string, options: CompileOptions): void {
11+
const warnHtmlMessage = isBoolean(options.warnHtmlMessage)
12+
? options.warnHtmlMessage
13+
: true
14+
if (warnHtmlMessage && RE_HTML_TAG.test(source)) {
15+
warn(format(WARN_MESSAGE, { source }))
16+
}
17+
}
18+
19+
const defaultOnCacheKey = (source: string): string => source
20+
let compileCache: unknown = Object.create(null)
21+
22+
/** @internal */
23+
export function clearCompileCache(): void {
24+
compileCache = Object.create(null)
25+
}
26+
27+
/** @internal */
28+
export function compileToFunction<T = string>(
29+
source: string,
30+
options: CompileOptions = {}
31+
): MessageFunction<T> {
32+
if (__RUNTIME__) {
33+
__DEV__ &&
34+
warn(
35+
`Runtime compilation is not supported in ${
36+
__BUNDLE_FILENAME__ || 'N/A'
37+
}.`
38+
)
39+
return (() => source) as MessageFunction<T>
40+
} else {
41+
// check HTML message
42+
__DEV__ && checkHtmlMessage(source, options)
43+
44+
// check caches
45+
const onCacheKey = options.onCacheKey || defaultOnCacheKey
46+
const key = onCacheKey(source)
47+
const cached = (compileCache as MessageFunctions<T>)[key]
48+
if (cached) {
49+
return cached
50+
}
51+
52+
// compile error detecting
53+
let occured = false
54+
const onError = options.onError || defaultOnError
55+
options.onError = (err: CompileError): void => {
56+
occured = true
57+
onError(err)
58+
}
59+
60+
// compile
61+
const { code } = baseCompile(source, options)
62+
63+
// evaluate function
64+
const msg = new Function(`return ${code}`)() as MessageFunction<T>
65+
66+
// if occured compile error, don't cache
67+
return !occured ? ((compileCache as MessageFunctions<T>)[key] = msg) : msg
68+
}
69+
}

packages/core/src/context.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
isPlainObject,
99
isObject
1010
} from '@intlify/shared'
11-
import { compile } from '@intlify/runtime'
1211
import { DevToolsTimelineEvents } from './debugger/constants'
1312
import { CoreWarnCodes, getWarnMessage } from './warnings'
1413

@@ -133,7 +132,7 @@ export interface CoreTranslationContext<Messages = {}, Message = string>
133132
processor: MessageProcessor<Message> | null
134133
warnHtmlMessage: boolean
135134
escapeParameter: boolean
136-
messageCompiler: MessageCompiler<Message>
135+
messageCompiler: MessageCompiler<Message> | null
137136
}
138137

139138
/** @internal */
@@ -188,6 +187,15 @@ function getDefaultLinkedModifiers<
188187
}
189188
}
190189

190+
let _compiler: unknown | null
191+
192+
/** @internal */
193+
export function registerMessageCompiler<Message>(
194+
compiler: MessageCompiler<Message>
195+
): void {
196+
_compiler = compiler
197+
}
198+
191199
/** @internal */
192200
export function createCoreContext<
193201
Message = string,
@@ -257,7 +265,7 @@ export function createCoreContext<
257265
const escapeParameter = !!options.escapeParameter
258266
const messageCompiler = isFunction(options.messageCompiler)
259267
? options.messageCompiler
260-
: compile
268+
: _compiler
261269
const onWarn = isFunction(options.onWarn) ? options.onWarn : warn
262270

263271
// setup internal options

packages/core/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1+
import { registerMessageCompiler } from './context'
2+
import { compileToFunction } from './compile'
3+
4+
// register message compiler at @intlify/core
5+
registerMessageCompiler(compileToFunction)
6+
17
export * from './context'
8+
export * from './compile'
29
export * from './translate'
310
export * from './datetime'
411
export * from './number'

packages/core/src/runtime.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// NOTE: for runtime only buidling & vue-i18n direct inmporting
2+
export * from './context'
3+
export * from './compile'
4+
export * from './translate'
5+
export * from './datetime'
6+
export * from './number'
7+
export * from './debugger'
8+
export * from './warnings'
9+
export * from './errors'
10+
export * from './types'

0 commit comments

Comments
 (0)