react-native-boost 1.0.0 → 1.1.0

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 CHANGED
@@ -20,10 +20,19 @@ The documentation is available at [react-native-boost.oss.kuatsu.de](https://rea
20
20
  The app in the `apps/example` directory serves as a benchmark for the performance of the plugin.
21
21
 
22
22
  <div align="center">
23
- <img src="./apps/docs/docs/introduction/img/benchmark-ios.png" width="500" />
23
+ <img src="./apps/docs/content/docs/information/img/benchmark-ios.png" width="500" />
24
24
  </div>
25
25
 
26
- More benchmarks are available in the [docs](https://react-native-boost.oss.kuatsu.de/docs/introduction/benchmarks).
26
+ More benchmarks are available in the [docs](https://react-native-boost.oss.kuatsu.de/docs/information/benchmarks).
27
+
28
+ ## Compatibility
29
+
30
+ | `react-native-boost` | React Native |
31
+ | -------------------- | ---------------- |
32
+ | `0.x` | All versions[^1] |
33
+ | `1.x` | `>=0.83` |
34
+
35
+ [^1]: Starting from React Native `0.80`, `react-native-boost@0` prints import deprecation warnings.
27
36
 
28
37
  ## Installation
29
38
 
@@ -59,11 +68,11 @@ yarn start --clear
59
68
 
60
69
  That's it! No imports in your code, rebuilding, or anything else is required.
61
70
 
62
- Optionally, you can configure the Babel plugin with a few options described in the [documentation](https://react-native-boost.oss.kuatsu.de/docs/babel-plugin/configure).
71
+ Optionally, you can configure the Babel plugin with a few options described in the [documentation](https://react-native-boost.oss.kuatsu.de/docs/configuration/configure).
63
72
 
64
73
  ## How it works
65
74
 
66
- A technical rundown of how the plugin works can be found in the [docs](https://react-native-boost.oss.kuatsu.de/docs/introduction/how-it-works).
75
+ A technical rundown of how the plugin works can be found in the [docs](https://react-native-boost.oss.kuatsu.de/docs/information/how-it-works).
67
76
 
68
77
  ## Contributing
69
78
 
@@ -40,17 +40,23 @@ const isIgnoredFile = (path, ignores) => {
40
40
  }
41
41
  return false;
42
42
  };
43
+ const isForcedLine = (path) => {
44
+ return hasDecoratorComment(path, "@boost-force");
45
+ };
43
46
  const isIgnoredLine = (path) => {
47
+ return hasDecoratorComment(path, "@boost-ignore");
48
+ };
49
+ function hasDecoratorComment(path, decorator) {
44
50
  var _a, _b, _c;
45
- if ((_a = path.node.leadingComments) == null ? void 0 : _a.some((comment) => comment.value.includes("@boost-ignore"))) {
51
+ if ((_a = path.node.leadingComments) == null ? void 0 : _a.some((comment) => comment.value.includes(decorator))) {
46
52
  return true;
47
53
  }
48
54
  const jsxElementPath = path.parentPath;
49
- if ((_b = jsxElementPath.node.leadingComments) == null ? void 0 : _b.some((comment) => comment.value.includes("@boost-ignore"))) {
55
+ if ((_b = jsxElementPath.node.leadingComments) == null ? void 0 : _b.some((comment) => comment.value.includes(decorator))) {
50
56
  return true;
51
57
  }
52
58
  const propertyPath = jsxElementPath.parentPath;
53
- if (propertyPath && propertyPath.isObjectProperty() && ((_c = propertyPath.node.leadingComments) == null ? void 0 : _c.some((comment) => comment.value.includes("@boost-ignore")))) {
59
+ if (propertyPath && propertyPath.isObjectProperty() && ((_c = propertyPath.node.leadingComments) == null ? void 0 : _c.some((comment) => comment.value.includes(decorator)))) {
54
60
  return true;
55
61
  }
56
62
  if (!jsxElementPath.parentPath) return false;
@@ -71,18 +77,18 @@ const isIgnoredLine = (path) => {
71
77
  ...expression.node.trailingComments || [],
72
78
  ...expression.node.innerComments || []
73
79
  ].map((comment) => comment.value.trim());
74
- if (comments.some((comment) => comment.includes("@boost-ignore"))) {
80
+ if (comments.some((comment) => comment.includes(decorator))) {
75
81
  return true;
76
82
  }
77
83
  }
78
84
  }
79
- if (sibling.node.leadingComments && sibling.node.leadingComments.some((comment) => comment.value.includes("@boost-ignore"))) {
85
+ if (sibling.node.leadingComments && sibling.node.leadingComments.some((comment) => comment.value.includes(decorator))) {
80
86
  return true;
81
87
  }
82
88
  break;
83
89
  }
84
90
  return false;
85
- };
91
+ }
86
92
  const isValidJSXComponent = (path, componentName) => {
87
93
  if (!types.isJSXIdentifier(path.node.name)) return false;
88
94
  const parent = path.parent;
@@ -736,16 +742,10 @@ const textBlacklistedProperties = /* @__PURE__ */ new Set([
736
742
  ]);
737
743
  const textOptimizer = (path, logger) => {
738
744
  if (!isValidJSXComponent(path, "Text")) return;
745
+ if (!isReactNativeImport(path, "Text")) return;
739
746
  const parent = path.parent;
740
- const skipReason = getFirstBailoutReason([
741
- {
742
- reason: "line is marked with @boost-ignore",
743
- shouldBail: () => isIgnoredLine(path)
744
- },
745
- {
746
- reason: "Text is not imported from react-native",
747
- shouldBail: () => !isReactNativeImport(path, "Text")
748
- },
747
+ const forced = isForcedLine(path);
748
+ const overridableChecks = [
749
749
  {
750
750
  reason: "contains blacklisted props",
751
751
  shouldBail: () => hasBlacklistedProperty(path, textBlacklistedProperties)
@@ -758,14 +758,24 @@ const textOptimizer = (path, logger) => {
758
758
  reason: "contains non-string children",
759
759
  shouldBail: () => hasInvalidChildren(path, parent)
760
760
  }
761
- ]);
762
- if (skipReason) {
763
- logger.skipped({
764
- component: "Text",
765
- path,
766
- reason: skipReason
767
- });
768
- return;
761
+ ];
762
+ if (forced) {
763
+ const overriddenReason = getFirstBailoutReason(overridableChecks);
764
+ if (overriddenReason) {
765
+ logger.forced({ component: "Text", path, reason: overriddenReason });
766
+ }
767
+ } else {
768
+ const skipReason = getFirstBailoutReason([
769
+ {
770
+ reason: "line is marked with @boost-ignore",
771
+ shouldBail: () => isIgnoredLine(path)
772
+ },
773
+ ...overridableChecks
774
+ ]);
775
+ if (skipReason) {
776
+ logger.skipped({ component: "Text", path, reason: skipReason });
777
+ return;
778
+ }
769
779
  }
770
780
  const hub = path.hub;
771
781
  const file = typeof hub === "object" && hub !== null && "file" in hub ? hub.file : void 0;
@@ -870,11 +880,14 @@ const ANSI_RESET = "\x1B[0m";
870
880
  const ANSI_GREEN = "\x1B[32m";
871
881
  const ANSI_YELLOW = "\x1B[33m";
872
882
  const ANSI_MAGENTA = "\x1B[35m";
883
+ const ANSI_RED = "\x1B[31m";
873
884
  const noopLogger = {
874
885
  optimized() {
875
886
  },
876
887
  skipped() {
877
888
  },
889
+ forced() {
890
+ },
878
891
  warning() {
879
892
  }
880
893
  };
@@ -888,6 +901,12 @@ const createLogger = ({ verbose, silent }) => {
888
901
  if (!verbose) return;
889
902
  writeLog("skipped", `Skipped ${payload.component} in ${formatPathLocation(payload.path)} (${payload.reason})`);
890
903
  },
904
+ forced(payload) {
905
+ writeLog(
906
+ "forced",
907
+ `Force-optimized ${payload.component} in ${formatPathLocation(payload.path)} (skipped bailout: ${payload.reason})`
908
+ );
909
+ },
891
910
  warning(payload) {
892
911
  const context = formatWarningContext(payload);
893
912
  const message = context.length > 0 ? `${context}: ${payload.message}` : payload.message;
@@ -916,6 +935,9 @@ function formatLevel(level) {
916
935
  if (level === "skipped") {
917
936
  return colorize("[skipped]", ANSI_YELLOW);
918
937
  }
938
+ if (level === "forced") {
939
+ return colorize("[forced]", ANSI_RED);
940
+ }
919
941
  return colorize("[warning]", ANSI_MAGENTA);
920
942
  }
921
943
  function colorize(value, colorCode) {
@@ -967,6 +989,7 @@ const viewBlacklistedProperties = /* @__PURE__ */ new Set([
967
989
  ]);
968
990
  const viewOptimizer = (path, logger, options) => {
969
991
  if (!isValidJSXComponent(path, "View")) return;
992
+ if (!isReactNativeImport(path, "View")) return;
970
993
  let ancestorClassification;
971
994
  const getAncestorClassification = () => {
972
995
  if (!ancestorClassification) {
@@ -974,15 +997,8 @@ const viewOptimizer = (path, logger, options) => {
974
997
  }
975
998
  return ancestorClassification;
976
999
  };
977
- const skipReason = getFirstBailoutReason([
978
- {
979
- reason: "line is marked with @boost-ignore",
980
- shouldBail: () => isIgnoredLine(path)
981
- },
982
- {
983
- reason: "View is not imported from react-native",
984
- shouldBail: () => !isReactNativeImport(path, "View")
985
- },
1000
+ const forced = isForcedLine(path);
1001
+ const overridableChecks = [
986
1002
  {
987
1003
  reason: "contains blacklisted props",
988
1004
  shouldBail: () => hasBlacklistedProperty(path, viewBlacklistedProperties)
@@ -995,14 +1011,24 @@ const viewOptimizer = (path, logger, options) => {
995
1011
  reason: "has unresolved ancestor and dangerous optimization is disabled",
996
1012
  shouldBail: () => getAncestorClassification() === "unknown" && (options == null ? void 0 : options.dangerouslyOptimizeViewWithUnknownAncestors) !== true
997
1013
  }
998
- ]);
999
- if (skipReason) {
1000
- logger.skipped({
1001
- component: "View",
1002
- path,
1003
- reason: skipReason
1004
- });
1005
- return;
1014
+ ];
1015
+ if (forced) {
1016
+ const overriddenReason = getFirstBailoutReason(overridableChecks);
1017
+ if (overriddenReason) {
1018
+ logger.forced({ component: "View", path, reason: overriddenReason });
1019
+ }
1020
+ } else {
1021
+ const skipReason = getFirstBailoutReason([
1022
+ {
1023
+ reason: "line is marked with @boost-ignore",
1024
+ shouldBail: () => isIgnoredLine(path)
1025
+ },
1026
+ ...overridableChecks
1027
+ ]);
1028
+ if (skipReason) {
1029
+ logger.skipped({ component: "View", path, reason: skipReason });
1030
+ return;
1031
+ }
1006
1032
  }
1007
1033
  const hub = path.hub;
1008
1034
  const file = typeof hub === "object" && hub !== null && "file" in hub ? hub.file : void 0;