react-native-boost 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/package.json +27 -14
- package/plugin/index.js +37 -9
- package/src/optimizers/text/index.ts +20 -7
- package/src/plugin.ts +3 -1
- package/src/types/index.ts +21 -1
- package/src/utils/logger.ts +3 -0
- package/src/utils/plugin-error.ts +6 -0
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ module.exports = {
|
|
|
30
30
|
};
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Optionally, you can configure the plugin to disable specific optimizations:
|
|
33
|
+
Optionally, you can configure the plugin to log optimized files to the console and disable specific optimizations:
|
|
34
34
|
|
|
35
35
|
```js
|
|
36
36
|
module.exports = {
|
|
@@ -38,6 +38,7 @@ module.exports = {
|
|
|
38
38
|
[
|
|
39
39
|
'react-native-boost/plugin',
|
|
40
40
|
{
|
|
41
|
+
verbose: true,
|
|
41
42
|
optimizations: {
|
|
42
43
|
text: false,
|
|
43
44
|
},
|
|
@@ -66,10 +67,10 @@ const MyComponent = () => (
|
|
|
66
67
|
</View>
|
|
67
68
|
);
|
|
68
69
|
|
|
69
|
-
//
|
|
70
|
+
// Automagically transformed to ✨
|
|
70
71
|
import React from 'react';
|
|
71
72
|
import { View } from 'react-native';
|
|
72
|
-
import { NativeText } from 'react-native/Libraries/
|
|
73
|
+
import { NativeText } from 'react-native/Libraries/Text/TextNativeComponent';
|
|
73
74
|
|
|
74
75
|
const MyComponent = () => (
|
|
75
76
|
<View>
|
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-boost",
|
|
3
3
|
"description": "🚀 Boost your React Native app's performance with a single line of code",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.4",
|
|
5
5
|
"main": "dist/plugin.js",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"react-native",
|
|
8
|
+
"ios",
|
|
9
|
+
"android",
|
|
10
|
+
"performance",
|
|
11
|
+
"optimization",
|
|
12
|
+
"bundle",
|
|
13
|
+
"optimize"
|
|
14
|
+
],
|
|
6
15
|
"scripts": {
|
|
7
16
|
"clean": "rm -rf plugin",
|
|
8
17
|
"build": "yarn clean && esbuild src/plugin.ts --bundle --outfile=plugin/index.js --platform=node",
|
|
@@ -10,8 +19,9 @@
|
|
|
10
19
|
"typecheck": "tsc --noEmit",
|
|
11
20
|
"lint": "eslint src/**/*.ts",
|
|
12
21
|
"format": "prettier --write .",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
22
|
+
"release": "release-it",
|
|
23
|
+
"prepack": "cp ../../README.md ./README.md",
|
|
24
|
+
"postpack": "rm ./README.md"
|
|
15
25
|
},
|
|
16
26
|
"files": [
|
|
17
27
|
"src",
|
|
@@ -35,32 +45,35 @@
|
|
|
35
45
|
"publishConfig": {
|
|
36
46
|
"registry": "https://registry.npmjs.org"
|
|
37
47
|
},
|
|
38
|
-
"
|
|
48
|
+
"dependencies": {
|
|
39
49
|
"@babel/core": "^7.25.0",
|
|
40
50
|
"@babel/helper-module-imports": "^7.25.0",
|
|
41
|
-
"@babel/helper-plugin-utils": "^7.25.0"
|
|
51
|
+
"@babel/helper-plugin-utils": "^7.25.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
42
54
|
"@babel/plugin-syntax-jsx": "^7.25.0",
|
|
43
55
|
"@babel/preset-typescript": "^7.25.0",
|
|
44
|
-
"@commitlint/cli": "^19.7.1",
|
|
45
|
-
"@commitlint/config-conventional": "^17.0.2",
|
|
46
|
-
"@eslint/js": "^9.21.0",
|
|
47
56
|
"@release-it/conventional-changelog": "^10.0.0",
|
|
48
57
|
"@types/babel__helper-module-imports": "^7.0.0",
|
|
49
58
|
"@types/babel__helper-plugin-utils": "^7.0.0",
|
|
50
59
|
"@types/node": "^20",
|
|
51
60
|
"babel-plugin-tester": "^11.0.4",
|
|
52
61
|
"esbuild": "^0.25.0",
|
|
53
|
-
"eslint": "^9.21.0",
|
|
54
|
-
"eslint-plugin-unicorn": "^57.0.0",
|
|
55
62
|
"globals": "^16.0.0",
|
|
56
|
-
"husky": "^9.1.7",
|
|
57
|
-
"lint-staged": "^15.4.3",
|
|
58
|
-
"prettier": "^3.5.2",
|
|
59
63
|
"release-it": "^18.1.2",
|
|
60
64
|
"typescript": "^5.7.3",
|
|
61
|
-
"typescript-eslint": "^8.24.1",
|
|
62
65
|
"vitest": "^3.0.6"
|
|
63
66
|
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"expo": "*",
|
|
69
|
+
"react": "*",
|
|
70
|
+
"react-native": "*"
|
|
71
|
+
},
|
|
72
|
+
"peerDependenciesMeta": {
|
|
73
|
+
"expo": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
64
77
|
"release-it": {
|
|
65
78
|
"git": {
|
|
66
79
|
"commitMessage": "chore: release ${version}",
|
package/plugin/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -32250,9 +32251,9 @@ var require_browser = __commonJS({
|
|
|
32250
32251
|
}
|
|
32251
32252
|
});
|
|
32252
32253
|
|
|
32253
|
-
// node_modules/has-flag/index.js
|
|
32254
|
+
// ../../node_modules/has-flag/index.js
|
|
32254
32255
|
var require_has_flag = __commonJS({
|
|
32255
|
-
"node_modules/has-flag/index.js"(exports2, module2) {
|
|
32256
|
+
"../../node_modules/has-flag/index.js"(exports2, module2) {
|
|
32256
32257
|
"use strict";
|
|
32257
32258
|
module2.exports = (flag, argv = process.argv) => {
|
|
32258
32259
|
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
@@ -32263,9 +32264,9 @@ var require_has_flag = __commonJS({
|
|
|
32263
32264
|
}
|
|
32264
32265
|
});
|
|
32265
32266
|
|
|
32266
|
-
// node_modules/supports-color/index.js
|
|
32267
|
+
// ../../node_modules/supports-color/index.js
|
|
32267
32268
|
var require_supports_color = __commonJS({
|
|
32268
|
-
"node_modules/supports-color/index.js"(exports2, module2) {
|
|
32269
|
+
"../../node_modules/supports-color/index.js"(exports2, module2) {
|
|
32269
32270
|
"use strict";
|
|
32270
32271
|
var os = require("os");
|
|
32271
32272
|
var tty = require("tty");
|
|
@@ -32371,7 +32372,7 @@ var require_node = __commonJS({
|
|
|
32371
32372
|
var tty = require("tty");
|
|
32372
32373
|
var util = require("util");
|
|
32373
32374
|
exports2.init = init;
|
|
32374
|
-
exports2.log =
|
|
32375
|
+
exports2.log = log2;
|
|
32375
32376
|
exports2.formatArgs = formatArgs;
|
|
32376
32377
|
exports2.save = save;
|
|
32377
32378
|
exports2.load = load;
|
|
@@ -32506,7 +32507,7 @@ var require_node = __commonJS({
|
|
|
32506
32507
|
}
|
|
32507
32508
|
return (/* @__PURE__ */ new Date()).toISOString() + " ";
|
|
32508
32509
|
}
|
|
32509
|
-
function
|
|
32510
|
+
function log2(...args) {
|
|
32510
32511
|
return process.stderr.write(util.formatWithOptions(exports2.inspectOpts, ...args) + "\n");
|
|
32511
32512
|
}
|
|
32512
32513
|
function save(namespaces) {
|
|
@@ -70363,7 +70364,18 @@ var import_helper_plugin_utils = __toESM(require_lib());
|
|
|
70363
70364
|
// src/optimizers/text/index.ts
|
|
70364
70365
|
var import_core = __toESM(require_lib27());
|
|
70365
70366
|
var import_helper_module_imports = __toESM(require_lib11());
|
|
70366
|
-
|
|
70367
|
+
|
|
70368
|
+
// src/utils/plugin-error.ts
|
|
70369
|
+
var PluginError = class extends Error {
|
|
70370
|
+
constructor(message) {
|
|
70371
|
+
super(`[react-native-boost] Babel plugin exception: ${message}`);
|
|
70372
|
+
this.name = "PluginError";
|
|
70373
|
+
}
|
|
70374
|
+
};
|
|
70375
|
+
|
|
70376
|
+
// src/optimizers/text/index.ts
|
|
70377
|
+
var textOptimizer = (path, log2 = () => {
|
|
70378
|
+
}) => {
|
|
70367
70379
|
if (!import_core.types.isJSXIdentifier(path.node.name)) return;
|
|
70368
70380
|
const parent = path.parent;
|
|
70369
70381
|
if (!import_core.types.isJSXElement(parent)) return;
|
|
@@ -70379,7 +70391,16 @@ var textOptimizer = (path) => {
|
|
|
70379
70391
|
}
|
|
70380
70392
|
if (hasBlacklistedProperties(path)) return;
|
|
70381
70393
|
if (!hasOnlyStringChildren(path, parent)) return;
|
|
70382
|
-
const
|
|
70394
|
+
const hub = path.hub;
|
|
70395
|
+
const file = typeof hub === "object" && hub !== null && "file" in hub ? hub.file : void 0;
|
|
70396
|
+
if (!file) {
|
|
70397
|
+
throw new PluginError("No file found in Babel hub");
|
|
70398
|
+
}
|
|
70399
|
+
if (!file.__optimized) {
|
|
70400
|
+
const filename = file.opts?.filename || "unknown file";
|
|
70401
|
+
log2(`Optimizing file: ${filename}`);
|
|
70402
|
+
file.__optimized = true;
|
|
70403
|
+
}
|
|
70383
70404
|
if (!file.__nativeTextImport) {
|
|
70384
70405
|
file.__nativeTextImport = (0, import_helper_module_imports.addNamed)(path, "NativeText", "react-native/Libraries/Text/TextNativeComponent");
|
|
70385
70406
|
}
|
|
@@ -70465,6 +70486,11 @@ function hasBlacklistedProperties(path) {
|
|
|
70465
70486
|
});
|
|
70466
70487
|
}
|
|
70467
70488
|
|
|
70489
|
+
// src/utils/logger.ts
|
|
70490
|
+
var log = (message) => {
|
|
70491
|
+
console.log(`[react-native-boost] ${message}`);
|
|
70492
|
+
};
|
|
70493
|
+
|
|
70468
70494
|
// src/plugin.ts
|
|
70469
70495
|
var plugin_default = (0, import_helper_plugin_utils.declare)((api) => {
|
|
70470
70496
|
api.assertVersion(7);
|
|
@@ -70473,7 +70499,9 @@ var plugin_default = (0, import_helper_plugin_utils.declare)((api) => {
|
|
|
70473
70499
|
visitor: {
|
|
70474
70500
|
JSXOpeningElement(path, state) {
|
|
70475
70501
|
const options = state.opts ?? {};
|
|
70476
|
-
|
|
70502
|
+
const logger = options.verbose ? log : () => {
|
|
70503
|
+
};
|
|
70504
|
+
if (options.optimizations?.text !== false) textOptimizer(path, logger);
|
|
70477
70505
|
}
|
|
70478
70506
|
}
|
|
70479
70507
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { NodePath, types as t } from '@babel/core';
|
|
2
2
|
import { addNamed } from '@babel/helper-module-imports';
|
|
3
|
-
import { Optimizer } from '../../types';
|
|
3
|
+
import { HubFile, Optimizer } from '../../types';
|
|
4
|
+
import PluginError from '../../utils/plugin-error';
|
|
4
5
|
|
|
5
|
-
export const textOptimizer: Optimizer = (path) => {
|
|
6
|
+
export const textOptimizer: Optimizer = (path, log = () => {}) => {
|
|
6
7
|
// Ensure we're processing a JSX Text element
|
|
7
8
|
if (!t.isJSXIdentifier(path.node.name)) return;
|
|
8
9
|
|
|
@@ -27,10 +28,22 @@ export const textOptimizer: Optimizer = (path) => {
|
|
|
27
28
|
if (!hasOnlyStringChildren(path, parent)) return;
|
|
28
29
|
// TODO: Don't bail if the element has a style prop
|
|
29
30
|
|
|
30
|
-
//
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// Extract the file from the Babel hub and add flags for logging & import caching
|
|
32
|
+
const hub = path.hub as unknown;
|
|
33
|
+
const file = typeof hub === 'object' && hub !== null && 'file' in hub ? (hub.file as HubFile) : undefined;
|
|
34
|
+
|
|
35
|
+
if (!file) {
|
|
36
|
+
throw new PluginError('No file found in Babel hub');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Log the file's optimized status only once
|
|
40
|
+
if (!file.__optimized) {
|
|
41
|
+
const filename = file.opts?.filename || 'unknown file';
|
|
42
|
+
log(`Optimizing file: ${filename}`);
|
|
43
|
+
file.__optimized = true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Add TextNativeComponent import (cached on file) so we only add it once per file
|
|
34
47
|
if (!file.__nativeTextImport) {
|
|
35
48
|
file.__nativeTextImport = addNamed(path, 'NativeText', 'react-native/Libraries/Text/TextNativeComponent');
|
|
36
49
|
}
|
|
@@ -105,7 +118,7 @@ function hasBlacklistedProperties(path: NodePath<t.JSXOpeningElement>): boolean
|
|
|
105
118
|
const binding = path.scope.getBinding(attribute.argument.name);
|
|
106
119
|
let objectExpression: t.ObjectExpression | undefined;
|
|
107
120
|
if (binding) {
|
|
108
|
-
// If the binding node is a VariableDeclarator, use its initializer
|
|
121
|
+
// If the binding node is a VariableDeclarator, use its initializer
|
|
109
122
|
if (t.isVariableDeclarator(binding.path.node)) {
|
|
110
123
|
objectExpression = binding.path.node.init as t.ObjectExpression;
|
|
111
124
|
} else if (t.isObjectExpression(binding.path.node)) {
|
package/src/plugin.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { declare } from '@babel/helper-plugin-utils';
|
|
2
2
|
import { textOptimizer } from './optimizers/text';
|
|
3
3
|
import { PluginOptions } from './types';
|
|
4
|
+
import { log } from './utils/logger';
|
|
4
5
|
|
|
5
6
|
export default declare((api) => {
|
|
6
7
|
api.assertVersion(7);
|
|
@@ -10,7 +11,8 @@ export default declare((api) => {
|
|
|
10
11
|
visitor: {
|
|
11
12
|
JSXOpeningElement(path, state) {
|
|
12
13
|
const options = (state.opts ?? {}) as PluginOptions;
|
|
13
|
-
|
|
14
|
+
const logger = options.verbose ? log : () => {};
|
|
15
|
+
if (options.optimizations?.text !== false) textOptimizer(path, logger);
|
|
14
16
|
},
|
|
15
17
|
},
|
|
16
18
|
};
|
package/src/types/index.ts
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
import { NodePath, types as t } from '@babel/core';
|
|
2
2
|
|
|
3
3
|
export interface PluginOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Whether or not to log optimized files to the console.
|
|
6
|
+
* @default false
|
|
7
|
+
*/
|
|
8
|
+
verbose?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* The optimizations to apply to the plugin.
|
|
11
|
+
*/
|
|
4
12
|
optimizations?: {
|
|
13
|
+
/**
|
|
14
|
+
* Whether or not to optimize the text component.
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
5
17
|
text?: boolean;
|
|
6
18
|
};
|
|
7
19
|
}
|
|
8
20
|
|
|
9
|
-
export type Optimizer = (path: NodePath<t.JSXOpeningElement
|
|
21
|
+
export type Optimizer = (path: NodePath<t.JSXOpeningElement>, log?: (message: string) => void) => void;
|
|
22
|
+
|
|
23
|
+
export type HubFile = t.File & {
|
|
24
|
+
opts: {
|
|
25
|
+
filename: string;
|
|
26
|
+
};
|
|
27
|
+
__nativeTextImport?: t.Identifier;
|
|
28
|
+
__optimized?: boolean;
|
|
29
|
+
};
|