expo-modules-autolinking 1.2.0 → 1.3.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/CHANGELOG.md CHANGED
@@ -10,7 +10,13 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
- ## 1.2.0 — 2023-04-13
13
+ ## 1.3.0 — 2023-05-08
14
+
15
+ ### 🎉 New features
16
+
17
+ - Generating `ExpoModulesProvider.swift` in the build phase script instead of only `pod install`. ([#21108](https://github.com/expo/expo/pull/21108) by [@tsapeta](https://github.com/tsapeta))
18
+
19
+ ## 1.2.0 - 2023-04-13
14
20
 
15
21
  ### 🎉 New features
16
22
 
package/README.md CHANGED
@@ -16,7 +16,7 @@ Scripts that autolink Expo modules.
16
16
 
17
17
  # Installation in managed Expo projects
18
18
 
19
- For [managed](https://docs.expo.dev/versions/latest/introduction/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects — it is likely to be included in an upcoming Expo SDK release.
19
+ For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects — it is likely to be included in an upcoming Expo SDK release.
20
20
 
21
21
  # Installation in bare React Native projects
22
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-modules-autolinking",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Scripts that autolink Expo modules.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -48,5 +48,5 @@
48
48
  "find-up": "^5.0.0",
49
49
  "fs-extra": "^9.1.0"
50
50
  },
51
- "gitHead": "362ed24e78a57e9839afd2925d2af4aff7e28437"
51
+ "gitHead": "4ba50c428c8369bb6b3a51a860d4898ad4ccbe78"
52
52
  }
@@ -103,6 +103,11 @@ module Expo
103
103
  @options.fetch(:providerName, Constants::MODULES_PROVIDER_FILE_NAME)
104
104
  end
105
105
 
106
+ # Absolute path to `Pods/Target Support Files/<pods target name>/<modules provider file>` within the project path
107
+ public def modules_provider_path(target)
108
+ File.join(target.support_files_dir, modules_provider_name)
109
+ end
110
+
106
111
  # For now there is no need to generate the modules provider for testing.
107
112
  public def should_generate_modules_provider?
108
113
  return !@options.fetch(:testsOnly, false)
@@ -126,20 +131,11 @@ module Expo
126
131
  end
127
132
  end
128
133
 
129
- private def node_command_args(command_name)
134
+ public def base_command_args
130
135
  search_paths = @options.fetch(:searchPaths, @options.fetch(:modules_paths, nil))
131
136
  ignore_paths = @options.fetch(:ignorePaths, nil)
132
137
  exclude = @options.fetch(:exclude, [])
133
-
134
- args = [
135
- 'node',
136
- '--no-warnings',
137
- '--eval',
138
- 'require(\'expo-modules-autolinking\')(process.argv.slice(1))',
139
- command_name,
140
- '--platform',
141
- 'ios'
142
- ]
138
+ args = []
143
139
 
144
140
  if !search_paths.nil? && !search_paths.empty?
145
141
  args.concat(search_paths)
@@ -156,11 +152,24 @@ module Expo
156
152
  args
157
153
  end
158
154
 
155
+ private def node_command_args(command_name)
156
+ eval_command_args = [
157
+ 'node',
158
+ '--no-warnings',
159
+ '--eval',
160
+ 'require(\'expo-modules-autolinking\')(process.argv.slice(1))',
161
+ command_name,
162
+ '--platform',
163
+ 'ios'
164
+ ]
165
+ return eval_command_args.concat(base_command_args())
166
+ end
167
+
159
168
  private def resolve_command_args
160
169
  node_command_args('resolve').concat(['--json'])
161
170
  end
162
171
 
163
- private def generate_package_list_command_args(target_path)
172
+ public def generate_package_list_command_args(target_path)
164
173
  node_command_args('generate-package-list').concat([
165
174
  '--target',
166
175
  target_path
@@ -3,5 +3,7 @@ module Expo
3
3
  module Constants
4
4
  GENERATED_GROUP_NAME = 'ExpoModulesProviders'
5
5
  MODULES_PROVIDER_FILE_NAME = 'ExpoModulesProvider.swift'
6
+ CONFIGURE_PROJECT_BUILD_SCRIPT_NAME = '[Expo] Configure project'
7
+ CONFIGURE_PROJECT_SCRIPT_FILE_NAME = 'expo-configure-project.sh'
6
8
  end
7
9
  end
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+ require 'colored2'
1
3
 
2
4
  module Expo
3
5
  module ProjectIntegrator
@@ -32,15 +34,15 @@ module Expo
32
34
  # The user target name (without `Pods-` prefix which is a part of `target.name`)
33
35
  target_name = target.target_definition.name
34
36
 
35
- UI.message '- Generating the provider for ' << target_name.green << ' target' do
36
- # PBXNativeTarget of the user target
37
- native_target = project.native_targets.find { |native_target| native_target.name == target_name }
37
+ # PBXNativeTarget of the user target
38
+ native_target = project.native_targets.find { |native_target| native_target.name == target_name }
38
39
 
39
- # Shorthand ref for the autolinking manager.
40
- autolinking_manager = target.target_definition.autolinking_manager
40
+ # Shorthand ref for the autolinking manager.
41
+ autolinking_manager = target.target_definition.autolinking_manager
41
42
 
42
- # Absolute path to `Pods/Target Support Files/<pods target name>/<modules provider file>` within the project path
43
- modules_provider_path = File.join(target.support_files_dir, autolinking_manager.modules_provider_name)
43
+ UI.message '- Generating the provider for ' << target_name.green << ' target' do
44
+ # Get the absolute path to the modules provider
45
+ modules_provider_path = autolinking_manager.modules_provider_path(target)
44
46
 
45
47
  # Run `expo-modules-autolinking` command to generate the file
46
48
  autolinking_manager.generate_package_list(target_name, modules_provider_path)
@@ -62,6 +64,8 @@ module Expo
62
64
  end
63
65
  end
64
66
  end
67
+
68
+ integrate_build_script(autolinking_manager, project, target, native_target)
65
69
  end
66
70
 
67
71
  # Remove the generated group if it has nothing left inside
@@ -128,5 +132,135 @@ module Expo
128
132
  end
129
133
  end
130
134
 
131
- end # module ExpoAutolinkingExtension
135
+ # Makes sure that the build script configuring the project is installed,
136
+ # is up-to-date and is placed before the "Compile Sources" phase.
137
+ def self.integrate_build_script(autolinking_manager, project, target, native_target)
138
+ build_phases = native_target.build_phases
139
+ modules_provider_path = autolinking_manager.modules_provider_path(target)
140
+
141
+ # Look for our own build script phase
142
+ xcode_build_script = native_target.shell_script_build_phases.find { |script|
143
+ script.name == Constants::CONFIGURE_PROJECT_BUILD_SCRIPT_NAME
144
+ }
145
+
146
+ if xcode_build_script.nil?
147
+ # Inform the user that we added a build script.
148
+ puts "[Expo] ".blue << "Installing the build script for target " << native_target.name.green
149
+
150
+ # Create a new build script in the target, it's added as the last phase
151
+ xcode_build_script = native_target.new_shell_script_build_phase(Constants::CONFIGURE_PROJECT_BUILD_SCRIPT_NAME)
152
+ end
153
+
154
+ # Make sure it is before the "Compile Sources" build phase
155
+ xcode_build_script_index = build_phases.find_index(xcode_build_script)
156
+ compile_sources_index = build_phases.find_index { |phase|
157
+ phase.is_a?(Xcodeproj::Project::PBXSourcesBuildPhase)
158
+ }
159
+
160
+ if xcode_build_script_index.nil?
161
+ # This is almost impossible to get here as the script was just created with `new_shell_script_build_phase`
162
+ # that puts the script at the end of the phases, but let's log it just in case.
163
+ puts "[Expo] ".blue << "Unable to find the configuring build script in the Xcode project".red
164
+ end
165
+
166
+ if compile_sources_index.nil?
167
+ # In this case the project will probably not compile but that's not our fault
168
+ # and it doesn't block us from updating our build script.
169
+ puts "[Expo] ".blue << "Unable to find the compilation build phase in the Xcode project".red
170
+ end
171
+
172
+ # Insert our script before the "Compile Sources" phase when necessary
173
+ unless compile_sources_index.nil? || xcode_build_script_index < compile_sources_index
174
+ build_phases.insert(
175
+ compile_sources_index,
176
+ build_phases.delete_at(xcode_build_script_index)
177
+ )
178
+ end
179
+
180
+ # Get path to the script that will be added to the target support files
181
+ support_script_path = File.join(target.support_files_dir, Constants::CONFIGURE_PROJECT_SCRIPT_FILE_NAME)
182
+ support_script_relative_path = Pathname.new(support_script_path).relative_path_from(project.project_dir)
183
+
184
+ # Write to the shell script so it's always in-sync with the autolinking configuration
185
+ IO.write(
186
+ support_script_path,
187
+ generate_support_script(autolinking_manager, modules_provider_path)
188
+ )
189
+
190
+ # Make the support script executable
191
+ FileUtils.chmod('+x', support_script_path)
192
+
193
+ # Force the build phase script to run on each build (including incremental builds)
194
+ xcode_build_script.always_out_of_date = '1'
195
+
196
+ # Make sure the build script in Xcode is up to date, but probably it's not going to change
197
+ # as it just runs the script generated in the target support files
198
+ xcode_build_script.shell_script = generate_xcode_build_script(support_script_relative_path)
199
+ end
200
+
201
+ # Generates the shell script of the build script phase.
202
+ # Try not to modify this since it involves changes in the pbxproj so
203
+ # it's better to modify the support script instead, if possible.
204
+ def self.generate_xcode_build_script(script_relative_path)
205
+ escaped_path = script_relative_path.to_s.gsub(/[^a-zA-Z0-9,\._\+@%\/\-]/) { |char| "\\#{char}" }
206
+
207
+ <<~XCODE_BUILD_SCRIPT
208
+ # This script configures Expo modules and generates the modules provider file.
209
+ bash -l -c "./#{escaped_path}"
210
+ XCODE_BUILD_SCRIPT
211
+ end
212
+
213
+ # Generates the support script that is executed by the build script phase.
214
+ def self.generate_support_script(autolinking_manager, modules_provider_path)
215
+ args = autolinking_manager.base_command_args.map { |arg| "\"#{arg}\"" }.join(' ')
216
+
217
+ <<~SUPPORT_SCRIPT
218
+ #!/usr/bin/env bash
219
+ # @generated by expo-modules-autolinking
220
+
221
+ set -eo pipefail
222
+
223
+ function with_node() {
224
+ # Start with a default
225
+ export NODE_BINARY=$(command -v node)
226
+
227
+ # Override the default with the global environment
228
+ ENV_PATH="$PODS_ROOT/../.xcode.env"
229
+ if [[ -f "$ENV_PATH" ]]; then
230
+ source "$ENV_PATH"
231
+ fi
232
+
233
+ # Override the global with the local environment
234
+ LOCAL_ENV_PATH="${ENV_PATH}.local"
235
+ if [[ -f "$LOCAL_ENV_PATH" ]]; then
236
+ source "$LOCAL_ENV_PATH"
237
+ fi
238
+
239
+ if [[ -n "$NODE_BINARY" && -x "$NODE_BINARY" ]]; then
240
+ echo "Node found at: ${NODE_BINARY}"
241
+ else
242
+ cat >&2 << NODE_NOT_FOUND
243
+ error: Could not find "node" executable while running an Xcode build script.
244
+ You need to specify the path to your Node.js executable by defining an environment variable named NODE_BINARY in your project's .xcode.env or .xcode.env.local file.
245
+ You can set this up quickly by running:
246
+
247
+ echo "export NODE_BINARY=\\$(command -v node)" >> .xcode.env
248
+
249
+ in the ios folder of your project.
250
+ NODE_NOT_FOUND
251
+
252
+ exit 1
253
+ fi
254
+
255
+ # Execute argument, if present
256
+ if [[ "$#" -gt 0 ]]; then
257
+ "$NODE_BINARY" "$@"
258
+ fi
259
+ }
260
+
261
+ with_node --no-warnings --eval "require(\'expo-modules-autolinking\')(process.argv.slice(1))" generate-package-list #{args} --target "#{modules_provider_path}"
262
+ SUPPORT_SCRIPT
263
+ end
264
+
265
+ end # module ProjectIntegrator
132
266
  end # module Expo