Skip to content

Commit

Permalink
feat: add babel-plugin-formatjs to babel-preset-mc-app (#3672)
Browse files Browse the repository at this point in the history
* feat: add `babel-plugin-formatjs` to `babel-preset-mc-app` and `mc-scripts`

# Conflicts:
#	pnpm-lock.yaml

* refactor: add  `i18nAst` flag

* test: add babel-plugin-formatjs test cases

# Conflicts:
#	pnpm-lock.yaml

* fix: describe opt-in flags
  • Loading branch information
ragafus authored Jan 7, 2025
1 parent a435e7f commit 5c33a40
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 85 deletions.
9 changes: 9 additions & 0 deletions .changeset/purple-rice-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@commercetools-frontend/babel-preset-mc-app': minor
'@commercetools-frontend/mc-scripts': minor
---

Add `babel-plugin-formatjs` to avoid bloating bundles with useless data from `formatjs` messages (`description`, `defaultMessage` props). Opt-in flags:

- i18nAst: pre-parse defaultMessage into AST for faster runtime perf
- i18nRemoveDefaultMessage: remove defaultMessage field in generated js after extraction
13 changes: 13 additions & 0 deletions packages/babel-preset-mc-app/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ const defaultOptions = {
// it explicitely. This will disable `core-js` for `preset-env` and the
// `plugin-transform-runtime`.
disableCoreJs: false,
// If `formatjs` should pre-parse defaultMessage into AST.
// https://formatjs.github.io/docs/tooling/babel-plugin/#ast
i18nAst: false,
// If `formatjs` default messages should be removed from the bundle or not.
// https://formatjs.github.io/docs/tooling/babel-plugin#removedefaultmessage
i18nRemoveDefaultMessage: false,
};

/* eslint-disable global-require */
Expand Down Expand Up @@ -189,6 +195,13 @@ module.exports = function createBabePresetConfigForMcApp(api, opts = {}, env) {
require('@emotion/babel-plugin').default,
// Cherry-pick Lodash modules
require('babel-plugin-lodash').default,
[
require('babel-plugin-formatjs').default,
{
ast: options.i18nAst,
removeDefaultMessage: options.i18nRemoveDefaultMessage,
},
],
].filter(Boolean),
};
};
1 change: 1 addition & 0 deletions packages/babel-preset-mc-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@emotion/babel-plugin": "^11.11.0",
"@emotion/babel-preset-css-prop": "^11.11.0",
"babel-plugin-dev-expression": "^0.2.3",
"babel-plugin-formatjs": "^10.5.25",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-macros": "^3.1.0",
"babel-plugin-preval": "^5.1.0",
Expand Down
94 changes: 94 additions & 0 deletions packages/babel-preset-mc-app/production.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { transformSync } from '@babel/core';
import getBabePresetConfigForMcAppForProduction from './production';

describe('babel-plugin-formatjs', () => {
const code = `
import { defineMessages } from 'react-intl';
const messages = defineMessages({
welcome: {
id: 'app.welcome',
defaultMessage: 'Welcome, {name}!',
description: 'Message to greet the user by name',
},
});
`;

it('should remove description by default', () => {
const config = getBabePresetConfigForMcAppForProduction(null);

const result = transformSync(code, {
filename: 'dummy-file-name.js',
presets: config.presets,
plugins: config.plugins,
});

expect(result.code).toMatchInlineSnapshot(`
""use strict";
var _reactIntl = require("react-intl");
const messages = (0, _reactIntl.defineMessages)({
welcome: {
id: "app.welcome",
defaultMessage: "Welcome, {name}!"
}
});"
`);
});

it('should remove defaultMessage when i18nRemoveDefaultMessage is true', () => {
const config = getBabePresetConfigForMcAppForProduction(null, {
i18nRemoveDefaultMessage: true,
});

const result = transformSync(code, {
filename: 'dummy-file-name.js',
presets: config.presets,
plugins: config.plugins,
});

expect(result.code).toMatchInlineSnapshot(`
""use strict";
var _reactIntl = require("react-intl");
const messages = (0, _reactIntl.defineMessages)({
welcome: {
id: "app.welcome"
}
});"
`);
});

it('should parse defaultMessage into AST when i18nAst is true', () => {
const config = getBabePresetConfigForMcAppForProduction(null, {
i18nAst: true,
});

const result = transformSync(code, {
filename: 'dummy-file-name.js',
presets: config.presets,
plugins: config.plugins,
});

expect(result.code).toMatchInlineSnapshot(`
""use strict";
var _reactIntl = require("react-intl");
const messages = (0, _reactIntl.defineMessages)({
welcome: {
id: "app.welcome",
defaultMessage: [{
"type": 0,
"value": "Welcome, "
}, {
"type": 1,
"value": "name"
}, {
"type": 0,
"value": "!"
}]
}
});"
`);
});
});
13 changes: 13 additions & 0 deletions packages/mc-scripts/src/commands/build-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ async function run() {
plugins: [
'@emotion/babel-plugin',
'@babel/plugin-proposal-do-expressions',
[
'babel-plugin-formatjs',
{
removeDefaultMessage:
// Remove default `formatjs` messages from bundles.
// TODO: make it a CLI option when Vite support becomes stable.
process.env.ENABLE_I18N_REMOVE_DEFAULT_MESSAGE === 'true',
ast:
// Enable pre-parse default `formatjs` messages into AST.
// TODO: make it a CLI option when Vite support becomes stable.
process.env.ENABLE_I18N_AST === 'true',
},
],
],
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const defaultToggleFlags: TWebpackConfigToggleFlagsForProduction = {
// it explicitely. This will disable `core-js` for `preset-env` and the
// `plugin-transform-runtime`.
disableCoreJs: false,
// Pre-parse default `formatjs` messages into AST
i18nAst: false,
// Remove default `formatjs` messages from bundles.
i18nRemoveDefaultMessage: false,
};
const defaultOptions: TWebpackConfigOptions<'production'> = {
entryPoint: paths.entryPoint,
Expand Down Expand Up @@ -255,6 +259,9 @@ function createWebpackConfigForProduction(
{
runtime: hasJsxRuntime() ? 'automatic' : 'classic',
disableCoreJs: mergedOptions.toggleFlags.disableCoreJs,
i18nAst: mergedOptions.toggleFlags.i18nAst,
i18nRemoveDefaultMessage:
mergedOptions.toggleFlags.i18nRemoveDefaultMessage,
},
],
],
Expand Down
8 changes: 8 additions & 0 deletions packages/mc-scripts/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ export type TWebpackConfigToggleFlagsForDevelopment = {
* `plugin-transform-runtime`.
*/
disableCoreJs?: boolean;
/**
* Pre-parse default `formatjs` messages into AST
*/
i18nAst?: boolean;
/**
* Remove default `formatjs` messages from bundles.
*/
i18nRemoveDefaultMessage?: boolean;
};

export type TWebpackConfigToggleFlagsForProduction =
Expand Down
Loading

0 comments on commit 5c33a40

Please sign in to comment.