babel-preset-expo 11.1.0-canary-20240628-1ba8152 → 11.1.0-canary-20240719-83ee47b

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.
@@ -73,7 +73,7 @@ function reactClientReferencesPlugin() {
73
73
  pushProxy(exportName);
74
74
  }
75
75
  }
76
- else if (!['InterfaceDeclaration', 'TypeAlias'].includes(exportPath.node.declaration.type)) {
76
+ else if (!['InterfaceDeclaration', 'TSTypeAliasDeclaration', 'TypeAlias'].includes(exportPath.node.declaration.type)) {
77
77
  // TODO: What is this type?
78
78
  console.warn('[babel-preset-expo] Unsupported export specifier for "use client":', exportPath.node.declaration.type);
79
79
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Copyright © 2024 650 Industries.
3
+ */
4
+ import { ConfigAPI, types } from '@babel/core';
5
+ export declare function detectDynamicExports(api: ConfigAPI & {
6
+ types: typeof types;
7
+ }): babel.PluginObj;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectDynamicExports = void 0;
4
+ const debug = require('debug')('expo:babel:exports');
5
+ // A babel pass to detect the usage of `module.exports` or `exports` in a module for use in
6
+ // export all expansion passes during tree shaking.
7
+ function detectDynamicExports(api) {
8
+ const { types: t } = api;
9
+ return {
10
+ name: 'expo-detect-dynamic-exports',
11
+ pre(file) {
12
+ assertExpoMetadata(file.metadata);
13
+ file.metadata.hasCjsExports = false;
14
+ },
15
+ visitor: {
16
+ // Any usage of `module.exports` or `exports` will mark the module as non-static.
17
+ // module.exports.a = 1;
18
+ // exports.a = 1;
19
+ CallExpression(path, state) {
20
+ assertExpoMetadata(state.file.metadata);
21
+ if (state.file.metadata.hasCjsExports)
22
+ return;
23
+ const callee = path.node.callee;
24
+ if (
25
+ // Object.assign(...)
26
+ t.isMemberExpression(callee) &&
27
+ t.isIdentifier(callee.object, { name: 'Object' }) &&
28
+ t.isIdentifier(callee.property, { name: 'assign' }) &&
29
+ // Allow `Object.assign(module.exports)` since it does nothing. Must have a second argument.
30
+ path.node.arguments.length > 1) {
31
+ const isModuleExports = t.isMemberExpression(path.node.arguments[0]) &&
32
+ t.isIdentifier(path.node.arguments[0].object, { name: 'module' }) &&
33
+ // Second argument is `exports` or 'exports'
34
+ // .exports
35
+ (t.isIdentifier(path.node.arguments[0].property, { name: 'exports' }) ||
36
+ // ['exports']
37
+ (t.isStringLiteral(path.node.arguments[0].property) &&
38
+ path.node.arguments[0].property.value === 'exports'));
39
+ // NOTE: Cannot match `['exp' + 'orts']`. We'd need to run after minification to match that confidently.
40
+ // Check for Object.assign(module.exports, ...), Object.assign(exports, ...)
41
+ if (
42
+ // module.exports
43
+ isModuleExports ||
44
+ // exports
45
+ t.isIdentifier(path.node.arguments[0], { name: 'exports' })) {
46
+ debug('Found Object.assign to module.exports or exports at ' + path.node.loc?.start.line);
47
+ state.file.metadata.hasCjsExports = true;
48
+ }
49
+ }
50
+ },
51
+ AssignmentExpression(path, state) {
52
+ assertExpoMetadata(state.file.metadata);
53
+ if (state.file.metadata.hasCjsExports)
54
+ return;
55
+ const left = path.node.left;
56
+ // Detect module.exports.foo = ... or exports.foo = ...
57
+ if ((t.isMemberExpression(left) &&
58
+ ((t.isIdentifier(left.object, { name: 'module' }) &&
59
+ (t.isIdentifier(left.property, { name: 'exports' }) ||
60
+ (t.isStringLiteral(left.property) && left.property.value === 'exports'))) ||
61
+ t.isIdentifier(left.object, { name: 'exports' }))) ||
62
+ ('object' in left &&
63
+ t.isMemberExpression(left.object) &&
64
+ t.isIdentifier(left.object.object, { name: 'module' }) &&
65
+ (t.isIdentifier(left.object.property, { name: 'exports' }) ||
66
+ (t.isStringLiteral(left.object.property) &&
67
+ left.object.property.value === 'exports')))) {
68
+ debug('Found assignment to module.exports or exports at ' + path.node.loc?.start.line);
69
+ state.file.metadata.hasCjsExports = true;
70
+ }
71
+ else if (t.isIdentifier(left, { name: 'exports' }) &&
72
+ path.scope.hasGlobal('exports') &&
73
+ // Ensure left is not defined in any scope
74
+ !path.scope.hasBinding('exports')) {
75
+ debug('Found assignment to exports at ' + path.node.loc?.start.line);
76
+ state.file.metadata.hasCjsExports = true;
77
+ }
78
+ },
79
+ },
80
+ };
81
+ }
82
+ exports.detectDynamicExports = detectDynamicExports;
83
+ function assertExpoMetadata(metadata) {
84
+ if (metadata && typeof metadata === 'object') {
85
+ return;
86
+ }
87
+ throw new Error('Expected Babel state.file.metadata to be an object');
88
+ }
@@ -7,14 +7,14 @@ const FORBIDDEN_REACT_SERVER_IMPORTS = ['client-only'];
7
7
  /** Prevent importing certain known imports in given environments. This is for sanity to ensure a module never accidentally gets imported unexpectedly. */
8
8
  function environmentRestrictedImportsPlugin(api) {
9
9
  const { types: t } = api;
10
- const isReactServer = api.caller(common_1.getIsReactServer);
11
- const forbiddenPackages = isReactServer
10
+ const isAnyServerEnvironment = api.caller(common_1.getIsReactServer) || api.caller(common_1.getIsServer);
11
+ const forbiddenPackages = isAnyServerEnvironment
12
12
  ? FORBIDDEN_REACT_SERVER_IMPORTS
13
13
  : FORBIDDEN_CLIENT_IMPORTS;
14
14
  function checkSource(source, path) {
15
15
  forbiddenPackages.forEach((forbiddenImport) => {
16
16
  if (source === forbiddenImport) {
17
- if (isReactServer) {
17
+ if (isAnyServerEnvironment) {
18
18
  throw path.buildCodeFrameError(`Importing '${forbiddenImport}' module is not allowed in a React server bundle. Add the "use client" directive to this file or one of the parent modules to allow importing this module.`);
19
19
  }
20
20
  else {
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Copyright © 2024 650 Industries.
3
+ */
1
4
  import { ConfigAPI, types } from '@babel/core';
2
5
  /**
3
6
  * Inlines environment variables to configure the process:
@@ -4,6 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.expoRouterBabelPlugin = void 0;
7
+ /**
8
+ * Copyright © 2024 650 Industries.
9
+ */
7
10
  const core_1 = require("@babel/core");
8
11
  const path_1 = __importDefault(require("path"));
9
12
  const resolve_from_1 = __importDefault(require("resolve-from"));
package/build/index.js CHANGED
@@ -89,15 +89,18 @@ function babelPresetExpo(api, options = {}) {
89
89
  // @see https://github.com/expo/expo/pull/11960#issuecomment-887796455
90
90
  extraPlugins.push([require('@babel/plugin-transform-object-rest-spread'), { loose: false }]);
91
91
  }
92
- else if (!isServerEnv) {
93
- // This is added back on hermes to ensure the react-jsx-dev plugin (`@babel/preset-react`) works as expected when
94
- // JSX is used in a function body. This is technically not required in production, but we
95
- // should retain the same behavior since it's hard to debug the differences.
96
- extraPlugins.push(require('@babel/plugin-transform-parameters'));
92
+ else {
93
+ if (platform !== 'web' && !isServerEnv) {
94
+ // This is added back on hermes to ensure the react-jsx-dev plugin (`@babel/preset-react`) works as expected when
95
+ // JSX is used in a function body. This is technically not required in production, but we
96
+ // should retain the same behavior since it's hard to debug the differences.
97
+ extraPlugins.push(require('@babel/plugin-transform-parameters'));
98
+ }
97
99
  }
98
100
  const inlines = {
99
101
  'process.env.EXPO_OS': platform,
100
102
  // 'typeof document': isServerEnv ? 'undefined' : 'object',
103
+ 'process.env.EXPO_SERVER': !!isServerEnv,
101
104
  };
102
105
  // `typeof window` is left in place for native + client environments.
103
106
  const minifyTypeofWindow = (platformOptions.minifyTypeofWindow ?? isServerEnv) || platform === 'web';
@@ -162,6 +165,9 @@ function babelPresetExpo(api, options = {}) {
162
165
  },
163
166
  ]);
164
167
  }
168
+ if (platformOptions.disableImportExportTransform) {
169
+ extraPlugins.push([require('./detect-dynamic-exports').detectDynamicExports]);
170
+ }
165
171
  // Use the simpler babel preset for web and server environments (both web and native SSR).
166
172
  const isModernEngine = platform === 'web' || isServerEnv;
167
173
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babel-preset-expo",
3
- "version": "11.1.0-canary-20240628-1ba8152",
3
+ "version": "11.1.0-canary-20240719-83ee47b",
4
4
  "description": "The Babel preset for Expo projects",
5
5
  "main": "build/index.js",
6
6
  "files": [
@@ -55,8 +55,8 @@
55
55
  },
56
56
  "devDependencies": {
57
57
  "@babel/core": "^7.20.0",
58
- "expo-module-scripts": "3.6.0-canary-20240628-1ba8152",
58
+ "expo-module-scripts": "3.6.0-canary-20240719-83ee47b",
59
59
  "jest": "^29.2.1"
60
60
  },
61
- "gitHead": "1ba815237ed606c5ee8488f68e49773fc9735cc3"
61
+ "gitHead": "83ee47b5c89c7f1b1a5101189580eaf3555f5962"
62
62
  }