Skip to content

Commit

Permalink
feat: expose a core bundle w/o parser (#1358)
Browse files Browse the repository at this point in the history
  • Loading branch information
longlho authored Jul 9, 2019
1 parent 61b536b commit 0a6ca3f
Show file tree
Hide file tree
Showing 23 changed files with 238 additions and 144 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ src/en.js
.idea/

# VS Code
.vscode
.vscode

core.js
core.d.ts
1 change: 1 addition & 0 deletions core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/core';
73 changes: 48 additions & 25 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ There are a few API layers that React Intl provides and is built on. When using
- [Message Syntax](#message-syntax)
- [Message Descriptor](#message-descriptor)
- [Message Formatting Fallbacks](#message-formatting-fallbacks)
- [Advanced Usage](#advanced-usage)
- [`formatMessage`](#formatmessage)
- [`formatHTMLMessage`](#formathtmlmessage)
- [React Intl Components](#react-intl-components)
- [Advanced Usage](#advanced-usage)
- [Core `react-intl`](#core-react-intl)
- [Caveats](#caveats)

<!-- tocstop -->

Expand Down Expand Up @@ -412,30 +414,6 @@ The message formatting APIs go the extra mile to provide fallbacks for the commo

Above, "source" refers to using the template as is, without any substitutions made.

#### Advanced Usage

For scenarios where performance is needed, you can pass in `messages` that contains `intl-messageformat`'s `AST` as values to `IntlProvider` to save compilation time when formatting messages. This is especially useful for:

1. Server-side rendering where you can cache the AST and don't have to pay compilation costs multiple time.
2. Desktop apps using Electron or CEF where you can preload/precompile things in advanced before runtime.

Example:

```tsx
import parser from 'intl-messageformat-parser';
import * as ReactDOM from 'react-dom';
const messages = {
ast_simple: parser.parse('hello world'),
ast_var: parser.parse('hello world, {name}'),
};

ReactDOM.render(
<IntlProvider messages={messages}>
<FormattedMessage id="ast_simple" />
</IntlProvider>
); // will render `hello world`
```

#### `formatMessage`

```js
Expand Down Expand Up @@ -483,3 +461,48 @@ The React components provided by React Intl allow for a declarative, idiomatic-R
**See:** The [Components][components] page.

[components]: Components.md

## Advanced Usage

### Core `react-intl`

We've also provided a core package that has the same API as the full `react-intl` package but without our parser. What this means is that you would have to pre-parse all messages into `AST` using [`intl-messageformat-parser`](https://www.npmjs.com/package/intl-messageformat-parser) and pass that into `IntlProvider`.

This is especially faster since it saves us time parsing `string` into `AST`. The use cases for this support are:

1. Server-side rendering or pre-parsing where you can cache the AST and don't have to pay compilation costs multiple time.
2. Desktop apps using Electron or CEF where you can preload/precompile things in advanced before runtime.

Example:

```tsx
// Pre-processed
import parser from 'intl-messageformat-parser';
const messages = {
ast_simple: parser.parse('hello world'),
ast_var: parser.parse('hello world, {name}'),
};

// During runtime
// ES6 import
import {IntlProvider, FormattedMessage} from 'react-intl/core';
import * as ReactDOM from 'react-dom';

ReactDOM.render(
<IntlProvider messages={messages}>
<FormattedMessage id="ast_simple" />
</IntlProvider>
); // will render `hello world`
```

The package size is also roughly 30% smaller:

| Package | Minified Size | Minzipped Size |
| ----------------- | ------------- | -------------- |
| `react-intl` | `29K` | `9.07K` |
| `react-intl.core` | `19K` | `6.32K` |

#### Caveats

- Since this approach uses `AST` as the data source, changes to `intl-messageformat-parser`'s `AST` will require cache invalidation
- `AST` is also larger in size than regular `string` messages but can be efficiently compressed
7 changes: 5 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
module.exports = {
preset: 'ts-jest/presets/js-with-babel',
testRegex: ['/test/functional/.*\\.(js|ts)', '/test/unit/.*\\.(js|ts)'],
testRegex: ['/test/(functional|unit)/.*\\.(ts|tsx)'],
testPathIgnorePatterns: ['test/functional/support', '/test/unit/testUtils'],
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'],
collectCoverageFrom: ['src/**/*.{ts,tsx}'],
coverageReporters: ['lcov', 'text', 'text-summary', 'html'],
transformIgnorePatterns: [
'/node_modules/(?!intl-messageformat|intl-messageformat-parser).+\\.js$',
],
coverageThreshold: {
global: {
branches: 85,
Expand Down
62 changes: 31 additions & 31 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@
"react": "global:React"
},
"dependencies": {
"@formatjs/intl-relativetimeformat": "^2.3.3",
"@formatjs/intl-relativetimeformat": "^2.3.4",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/invariant": "^2.2.30",
"@types/react": "^16.8.23",
"hoist-non-react-statics": "^3.3.0",
"intl-format-cache": "^4.0.0",
"intl-locales-supported": "^1.3.3",
"intl-messageformat-parser": "^2.0.0",
"intl-messageformat": "^5.0.0",
"intl-format-cache": "^4.0.1",
"intl-locales-supported": "^1.3.4",
"intl-messageformat": "^5.0.1",
"intl-messageformat-parser": "^2.0.1",
"invariant": "^2.1.1",
"react": "^16.3.0",
"shallow-equal": "^1.1.0"
Expand All @@ -54,10 +54,10 @@
"@babel/core": "^7.5.0",
"@babel/node": "^7.5.0",
"@babel/plugin-proposal-class-properties": "^7.5.0",
"@babel/plugin-proposal-object-rest-spread": "^7.5.2",
"@babel/plugin-proposal-object-rest-spread": "^7.5.3",
"@babel/plugin-transform-async-to-generator": "^7.5.0",
"@babel/plugin-transform-modules-commonjs": "^7.5.0",
"@babel/preset-env": "^7.5.2",
"@babel/preset-env": "^7.5.3",
"@babel/preset-react": "^7.0.0",
"@types/benchmark": "^1.0.31",
"@types/enzyme": "^3.10.1",
Expand All @@ -67,7 +67,7 @@
"@typescript-eslint/eslint-plugin": "^1.10.2",
"@typescript-eslint/parser": "^1.10.2",
"babel-jest": "^24.8.0",
"babel-plugin-react-intl": "^4.0.0",
"babel-plugin-react-intl": "^4.0.1",
"babel-plugin-transform-member-expression-literals": "^6.9.4",
"babel-plugin-transform-property-literals": "^6.9.4",
"babel-plugin-transform-react-remove-prop-types": "^0.4.18",
Expand Down Expand Up @@ -96,7 +96,7 @@
"prop-types": "^15.7.2",
"react-dom": "^16.8.6",
"rimraf": "^2.4.2",
"rollup": "^1.16.6",
"rollup": "^1.16.7",
"rollup-plugin-commonjs": "^10.0.1",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.0.0",
Expand All @@ -112,13 +112,13 @@
"watchify": "^3.7.0"
},
"scripts": {
"benchmark": "NODE_ENV=production TS_NODE_PROJECT='test/perf/tsconfig.json' ts-node test/perf/index.tsx",
"benchmark": "NODE_ENV=production TS_NODE_PROJECT='./tsconfig.cjs.json' ts-node test/perf/index.tsx",
"build:dist:dev": "cross-env NODE_ENV=development rollup -c rollup.config.dist.js",
"build:dist:prod": "cross-env NODE_ENV=production rollup -c rollup.config.dist.js",
"build:dist": "npm run build:dist:dev && npm run build:dist:prod",
"build:lib": "tsc && tsc -p tsconfig.cjs.json",
"build:lib": "tsc -p src/tsconfig.json && tsc -p src/tsconfig.cjs.json && tsc -p tsconfig.core.json",
"build": "npm run build:lib && npm run build:dist",
"clean": "rimraf src/en.js coverage/ dist/ lib/ test/renderer.js",
"clean": "rimraf coverage/ dist/ lib/ core.js core.d.ts",
"examples:install": "babel-node scripts/examples npm install",
"examples:link": "npm link && babel-node scripts/examples npm link react-intl",
"format:fix": "prettier --write '**/*.{js,md,jsx,ts,tsx}'",
Expand Down
Loading

0 comments on commit 0a6ca3f

Please sign in to comment.