create-pika-minigame 2.6.0 → 2.6.2

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/bin/cli.js CHANGED
@@ -222,10 +222,12 @@ ${colors.reset}
222
222
  // Copy scripts folder
223
223
  if (fs.existsSync(scriptsTemplateDir)) {
224
224
  copyDir(scriptsTemplateDir, path.join(targetDir, 'scripts'), replacements);
225
- // Make deploy script executable
226
- const deployScript = path.join(targetDir, 'scripts', 'deploy-vercel.sh');
227
- if (fs.existsSync(deployScript)) {
228
- fs.chmodSync(deployScript, '755');
225
+ // Make shell scripts executable
226
+ const scriptsDir = path.join(targetDir, 'scripts');
227
+ for (const file of fs.readdirSync(scriptsDir)) {
228
+ if (file.endsWith('.sh')) {
229
+ fs.chmodSync(path.join(scriptsDir, file), '755');
230
+ }
229
231
  }
230
232
  }
231
233
 
@@ -253,63 +255,96 @@ ${colors.reset}
253
255
  const pkgPath = path.join(targetDir, 'package.json');
254
256
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
255
257
 
258
+ // Only keep peer dependencies - actual deps come from pika-build workspace
256
259
  pkg.dependencies = {
257
- ...pkg.dependencies,
258
- 'react-native-gesture-handler': '~2.20.0',
260
+ react: pkg.dependencies.react,
261
+ 'react-native': pkg.dependencies['react-native'],
262
+ };
263
+
264
+ // These are peerDependencies for the game
265
+ pkg.peerDependencies = {
266
+ 'react': '18.3.1',
267
+ 'react-native': '0.77.0',
259
268
  'react-native-reanimated': '~3.16.0',
260
- 'react-native-safe-area-context': '4.12.0',
261
269
  };
262
270
 
263
271
  pkg.devDependencies = {
264
272
  ...pkg.devDependencies,
265
- '@callstack/repack': '^5.2.5',
266
- '@callstack/repack-plugin-reanimated': '^5.2.5',
267
- '@module-federation/enhanced': '^2.7.0',
268
- '@rspack/core': '^1.7.12',
269
- '@swc/helpers': '^0.5.19',
270
- 'ajv': '^8.17.0',
273
+ '@types/react': '~18.3.0',
274
+ 'typescript': '~5.3.0',
271
275
  'serve': '^14.2.0',
276
+ 'eslint': '^8.0.0',
272
277
  };
273
278
 
274
- // Add build and deploy scripts
279
+ // Add build and deploy scripts (use pika-build.sh for MF compatibility)
275
280
  pkg.scripts = {
276
281
  ...pkg.scripts,
277
- 'build:ios': `npx react-native webpack-bundle --platform ios --entry-file index.js --dev false --bundle-output build/outputs/ios/remotes/${snakeName}.container.js.bundle`,
278
- 'build:android': `npx react-native webpack-bundle --platform android --entry-file index.js --dev false --bundle-output build/outputs/android/remotes/${snakeName}.container.js.bundle`,
282
+ 'build:ios': './scripts/pika-build.sh ios',
283
+ 'build:android': './scripts/pika-build.sh android',
279
284
  'build:all': 'npm run build:ios && npm run build:android',
280
285
  'serve:ios': 'npx serve build/outputs/ios/remotes -l 9000 --cors',
281
286
  'serve:android': 'npx serve build/outputs/android/remotes -l 9000 --cors',
287
+ 'dev': 'npm run build:ios && npm run serve:ios',
282
288
  'deploy': './scripts/deploy-vercel.sh',
283
289
  'deploy:prod': './scripts/deploy-vercel.sh --prod',
284
290
  };
285
291
 
286
292
  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
287
293
 
288
- log.step(5, 'Project created successfully!');
294
+ // Step 5: Update .gitignore for Vercel
295
+ log.step(5, 'Updating .gitignore...');
296
+ const gitignorePath = path.join(targetDir, '.gitignore');
297
+ if (fs.existsSync(gitignorePath)) {
298
+ let gitignore = fs.readFileSync(gitignorePath, 'utf8');
299
+ if (!gitignore.includes('.vercel-prod-url')) {
300
+ gitignore += `
301
+ # Vercel
302
+ .vercel
303
+ .vercel-prod-url
304
+
305
+ # Build outputs
306
+ build/
307
+ `;
308
+ fs.writeFileSync(gitignorePath, gitignore);
309
+ log.success('Updated .gitignore');
310
+ }
311
+ }
312
+
313
+ log.step(6, 'Project created successfully!');
289
314
 
290
315
  console.log(`
291
316
  ${colors.green}Success!${colors.reset} Created ${colors.bright}${pascalName}${colors.reset} at ${targetDir}
292
317
 
318
+ ${colors.bright}Prerequisites:${colors.reset}
319
+
320
+ Make sure you have the Pika host repo cloned at ~/robotapp (or set PIKA_HOST_DIR)
321
+ The build script uses the host's node_modules for Module Federation compatibility.
322
+
293
323
  ${colors.bright}Next steps:${colors.reset}
294
324
 
295
325
  ${colors.cyan}cd ${projectName}${colors.reset}
296
- ${colors.cyan}npm install --legacy-peer-deps${colors.reset}
297
- ${colors.cyan}cd ios && pod install && cd ..${colors.reset}
298
- ${colors.cyan}npm run ios${colors.reset}
326
+ ${colors.cyan}npm install${colors.reset}
327
+ ${colors.cyan}npm run build:ios${colors.reset} # Build the game
328
+ ${colors.cyan}npm run serve:ios${colors.reset} # Serve on port 9000
299
329
 
300
330
  ${colors.bright}Available commands:${colors.reset}
301
331
 
302
- ${colors.cyan}npm run ios${colors.reset} Run on iOS simulator
303
- ${colors.cyan}npm run android${colors.reset} Run on Android emulator
304
- ${colors.cyan}npm start${colors.reset} Start Metro bundler
305
- ${colors.cyan}npm run deploy${colors.reset} Deploy to Vercel (preview)
306
- ${colors.cyan}npm run deploy:prod${colors.reset} Deploy to Vercel (production)
332
+ ${colors.cyan}npm run build:ios${colors.reset} Build for iOS (uses pika-build.sh)
333
+ ${colors.cyan}npm run build:android${colors.reset} Build for Android
334
+ ${colors.cyan}npm run serve:ios${colors.reset} Serve build on localhost:9000
335
+ ${colors.cyan}npm run dev${colors.reset} Build + serve (one command)
336
+ ${colors.cyan}npm run deploy${colors.reset} Deploy to Vercel (preview)
337
+ ${colors.cyan}npm run deploy:prod${colors.reset} Deploy to Vercel (production)
307
338
 
308
339
  ${colors.bright}Project structure:${colors.reset}
309
340
 
310
341
  src/ Game source code (edit this!)
311
- dev/ Development helpers (MockHost)
312
- scripts/ Deploy scripts
342
+ scripts/ Build and deploy scripts
343
+
344
+ ${colors.bright}Environment:${colors.reset}
345
+
346
+ PIKA_HOST_DIR Path to robotapp (default: ~/robotapp)
347
+ MF_PUBLIC_PATH Public URL for production builds
313
348
 
314
349
  Happy coding! ${colors.yellow}🎮${colors.reset}
315
350
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-pika-minigame",
3
- "version": "2.6.0",
3
+ "version": "2.6.2",
4
4
  "description": "CLI to scaffold Pika mini-game projects (bare React Native 0.77)",
5
5
  "author": "Pika Team",
6
6
  "license": "MIT",
@@ -5,32 +5,28 @@
5
5
  "description": "Pika mini-game: {{PROJECT_NAME_PASCAL}}",
6
6
  "main": "index.js",
7
7
  "scripts": {
8
- "start": "react-native start",
9
- "ios": "react-native run-ios",
10
- "android": "react-native run-android",
11
- "build:ios": "npx react-native webpack-bundle --platform ios --entry-file index.js --dev false --bundle-output build/outputs/ios/remotes/{{PROJECT_NAME_SNAKE}}.container.js.bundle",
12
- "build:android": "npx react-native webpack-bundle --platform android --entry-file index.js --dev false --bundle-output build/outputs/android/remotes/{{PROJECT_NAME_SNAKE}}.container.js.bundle",
8
+ "build:ios": "./scripts/pika-build.sh ios",
9
+ "build:android": "./scripts/pika-build.sh android",
10
+ "build:ios:prod": "./scripts/pika-build.sh ios --prod",
11
+ "build:android:prod": "./scripts/pika-build.sh android --prod",
13
12
  "build:all": "npm run build:ios && npm run build:android",
14
13
  "serve:ios": "npx serve build/outputs/ios/remotes -l 9000 --cors",
15
14
  "serve:android": "npx serve build/outputs/android/remotes -l 9000 --cors",
16
15
  "deploy": "./scripts/deploy-vercel.sh",
17
16
  "deploy:prod": "./scripts/deploy-vercel.sh --prod",
17
+ "dev": "npm run build:ios && npm run serve:ios",
18
18
  "lint": "eslint src/",
19
19
  "typecheck": "tsc --noEmit"
20
20
  },
21
- "dependencies": {
21
+ "peerDependencies": {
22
22
  "react": "18.3.1",
23
23
  "react-native": "0.77.0",
24
- "react-native-gesture-handler": "~2.20.0",
25
- "react-native-reanimated": "~3.16.0",
26
- "react-native-safe-area-context": "4.12.0",
27
- "react-native-screens": "~4.0.0"
24
+ "react-native-reanimated": "~3.16.0"
28
25
  },
29
26
  "devDependencies": {
30
- "@babel/core": "^7.25.0",
31
- "@callstack/repack": "^5.0.0",
32
27
  "@types/react": "~18.3.0",
33
28
  "typescript": "~5.3.0",
34
- "serve": "^14.2.0"
29
+ "serve": "^14.2.0",
30
+ "eslint": "^8.0.0"
35
31
  }
36
32
  }
@@ -62,6 +62,8 @@ export default Repack.defineRspackConfig((env) => {
62
62
  './App': './src/App.tsx',
63
63
  },
64
64
  shared: {
65
+ // eager: false = load from host's share scope (smaller bundle)
66
+ // Requires building with pika-build.sh to ensure correct paths
65
67
  react: { singleton: true, eager: false, requiredVersion: '18.3.1' },
66
68
  'react-native': { singleton: true, eager: false, requiredVersion: '0.77.0' },
67
69
  'react-native-reanimated': { singleton: true, eager: false },
@@ -8,6 +8,12 @@ set -e
8
8
  # Usage:
9
9
  # ./scripts/deploy-vercel.sh [--prod]
10
10
  #
11
+ # First deploy creates a new Vercel project and saves the production URL.
12
+ # Subsequent deploys use the saved URL automatically.
13
+ #
14
+ # To reset and create a new Vercel project:
15
+ # rm -rf .vercel .vercel-prod-url && ./scripts/deploy-vercel.sh --prod
16
+ #
11
17
  # Prerequisites:
12
18
  # - Vercel CLI: npm i -g vercel
13
19
  # - Logged in: vercel login
@@ -34,9 +40,24 @@ fi
34
40
 
35
41
  # Parse arguments
36
42
  PROD_FLAG=""
43
+ PROD_URL_FILE=".vercel-prod-url"
44
+
37
45
  if [[ "$1" == "--prod" ]]; then
38
46
  PROD_FLAG="--prod"
39
47
  log_info "Deploying to PRODUCTION"
48
+
49
+ # Check for saved production URL (project-local)
50
+ if [[ -f "$PROD_URL_FILE" ]]; then
51
+ SAVED_PROD_URL=$(cat "$PROD_URL_FILE" | tr -d '[:space:]')
52
+ if [[ -n "$SAVED_PROD_URL" ]]; then
53
+ log_info "Using saved production URL: $SAVED_PROD_URL"
54
+ VERCEL_PROD_URL="$SAVED_PROD_URL"
55
+ fi
56
+ fi
57
+
58
+ if [[ -z "$VERCEL_PROD_URL" ]]; then
59
+ log_info "No saved production URL found. Will detect after first deploy."
60
+ fi
40
61
  else
41
62
  log_info "Deploying to PREVIEW (add --prod for production)"
42
63
  fi
@@ -48,7 +69,7 @@ PROJECT_VERSION=$(node -p "require('./package.json').version")
48
69
  log_info "Project: $PROJECT_NAME v$PROJECT_VERSION"
49
70
 
50
71
  # =============================================================================
51
- # Step 1: Build for all platforms
72
+ # Step 1: Build for all platforms using pika-build.sh
52
73
  # =============================================================================
53
74
  log_info "Building mini-game bundles..."
54
75
 
@@ -57,24 +78,14 @@ BUILD_DIR="build/deploy"
57
78
  rm -rf "$BUILD_DIR"
58
79
  mkdir -p "$BUILD_DIR/ios" "$BUILD_DIR/android"
59
80
 
60
- # We'll set MF_PUBLIC_PATH after we know the Vercel URL
61
- # For now, build with a placeholder that we'll update
81
+ # Use pika-build.sh which builds in host's workspace for MF compatibility
82
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
62
83
 
63
84
  log_info "Building iOS bundle..."
64
- npx react-native webpack-bundle \
65
- --platform ios \
66
- --entry-file index.js \
67
- --dev false \
68
- --bundle-output build/outputs/ios/remotes/${PROJECT_NAME//-/_}.container.js.bundle \
69
- 2>&1 | tail -5
85
+ "$SCRIPT_DIR/pika-build.sh" ios 2>&1 | tail -10
70
86
 
71
87
  log_info "Building Android bundle..."
72
- npx react-native webpack-bundle \
73
- --platform android \
74
- --entry-file index.js \
75
- --dev false \
76
- --bundle-output build/outputs/android/remotes/${PROJECT_NAME//-/_}.container.js.bundle \
77
- 2>&1 | tail -5
88
+ "$SCRIPT_DIR/pika-build.sh" android 2>&1 | tail -10
78
89
 
79
90
  # Copy to deploy directory with platform subdirs
80
91
  cp -r build/outputs/ios/remotes/* "$BUILD_DIR/ios/"
@@ -147,9 +158,12 @@ log_success "Build complete: $BUILD_DIR"
147
158
  # =============================================================================
148
159
  log_info "Deploying to Vercel..."
149
160
 
150
- # Deploy and capture the URL
161
+ # First deploy to get the project linked and get a URL
162
+ log_info "Initial deployment..."
151
163
  DEPLOY_OUTPUT=$(vercel "$BUILD_DIR" $PROD_FLAG --yes 2>&1)
152
- DEPLOY_URL=$(echo "$DEPLOY_OUTPUT" | grep -E "https://" | tail -1 | tr -d ' ')
164
+
165
+ # Extract URL more carefully - look for vercel.app deployment URLs
166
+ DEPLOY_URL=$(echo "$DEPLOY_OUTPUT" | grep -oE 'https://[a-zA-Z0-9._-]+\.vercel\.app' | head -1)
153
167
 
154
168
  if [[ -z "$DEPLOY_URL" ]]; then
155
169
  log_error "Failed to get deployment URL"
@@ -157,10 +171,80 @@ if [[ -z "$DEPLOY_URL" ]]; then
157
171
  exit 1
158
172
  fi
159
173
 
174
+ # For production, use VERCEL_PROD_URL if set, otherwise try to auto-detect
175
+ if [[ "$PROD_FLAG" == "--prod" ]]; then
176
+ if [[ -n "$VERCEL_PROD_URL" ]]; then
177
+ # Use the saved/provided production URL
178
+ DEPLOY_URL="$VERCEL_PROD_URL"
179
+ log_info "Using production URL: $DEPLOY_URL"
180
+ else
181
+ log_info "Detecting production alias from Vercel..."
182
+
183
+ # Try to get alias from the deployed URL
184
+ PROD_DOMAIN=$(vercel inspect "$DEPLOY_URL" --json 2>/dev/null | node -e "
185
+ const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'));
186
+ const alias = data.alias || data.aliases || [];
187
+ const prod = Array.isArray(alias) ? alias[0] : alias;
188
+ if (prod) console.log(prod);
189
+ " 2>/dev/null || echo "")
190
+
191
+ if [[ -n "$PROD_DOMAIN" ]]; then
192
+ PROD_DOMAIN=$(echo "$PROD_DOMAIN" | sed 's|^https://||')
193
+ DEPLOY_URL="https://$PROD_DOMAIN"
194
+ log_info "Detected production alias: $DEPLOY_URL"
195
+ else
196
+ # Use the deployment URL as-is (first deploy)
197
+ log_info "Using deployment URL as production URL: $DEPLOY_URL"
198
+ fi
199
+
200
+ # Save for future deploys
201
+ echo "$DEPLOY_URL" > "$PROD_URL_FILE"
202
+ log_success "Saved production URL to $PROD_URL_FILE"
203
+ fi
204
+ fi
205
+
206
+ log_info "Deployment URL: $DEPLOY_URL"
207
+
208
+ # =============================================================================
209
+ # Step 3: Update mf-manifest.json with correct publicPath and redeploy
210
+ # =============================================================================
211
+ log_info "Updating publicPath in manifests..."
212
+
213
+ # Update iOS manifest
214
+ if [[ -f "$BUILD_DIR/ios/mf-manifest.json" ]]; then
215
+ node -e "
216
+ const fs = require('fs');
217
+ const manifest = JSON.parse(fs.readFileSync('$BUILD_DIR/ios/mf-manifest.json', 'utf8'));
218
+ manifest.metaData.publicPath = '$DEPLOY_URL/ios/';
219
+ fs.writeFileSync('$BUILD_DIR/ios/mf-manifest.json', JSON.stringify(manifest, null, 2));
220
+ console.log('Updated iOS publicPath to: $DEPLOY_URL/ios/');
221
+ "
222
+ fi
223
+
224
+ # Update Android manifest
225
+ if [[ -f "$BUILD_DIR/android/mf-manifest.json" ]]; then
226
+ node -e "
227
+ const fs = require('fs');
228
+ const manifest = JSON.parse(fs.readFileSync('$BUILD_DIR/android/mf-manifest.json', 'utf8'));
229
+ manifest.metaData.publicPath = '$DEPLOY_URL/android/';
230
+ fs.writeFileSync('$BUILD_DIR/android/mf-manifest.json', JSON.stringify(manifest, null, 2));
231
+ console.log('Updated Android publicPath to: $DEPLOY_URL/android/');
232
+ "
233
+ fi
234
+
235
+ # Redeploy with updated manifests
236
+ log_info "Redeploying with updated manifests..."
237
+ FINAL_OUTPUT=$(vercel "$BUILD_DIR" $PROD_FLAG --yes 2>&1)
238
+ FINAL_URL=$(echo "$FINAL_OUTPUT" | grep -oE 'https://[a-zA-Z0-9._-]+\.vercel\.app' | head -1)
239
+
240
+ if [[ -n "$FINAL_URL" ]]; then
241
+ DEPLOY_URL="$FINAL_URL"
242
+ fi
243
+
160
244
  log_success "Deployed to: $DEPLOY_URL"
161
245
 
162
246
  # =============================================================================
163
- # Step 3: Show integration info
247
+ # Step 4: Show integration info
164
248
  # =============================================================================
165
249
  echo ""
166
250
  echo "=============================================="
@@ -0,0 +1,112 @@
1
+ #!/bin/bash
2
+ #
3
+ # Pika Mini-Game Build Script
4
+ #
5
+ # Builds the mini-game using the Pika host's build environment to ensure
6
+ # Module Federation compatibility.
7
+ #
8
+ # Usage:
9
+ # ./scripts/pika-build.sh ios
10
+ # ./scripts/pika-build.sh android
11
+ #
12
+
13
+ set -e
14
+
15
+ PLATFORM=${1:-ios}
16
+
17
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
18
+ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
19
+ PROJECT_NAME=$(node -e "console.log(require('./app.json').name)" 2>/dev/null || basename "$PROJECT_DIR" | sed 's/-/_/g')
20
+
21
+ # Pika host repo - contains the correct node_modules
22
+ # Change this to your robotapp location or set PIKA_HOST_DIR env var
23
+ PIKA_HOST_DIR="${PIKA_HOST_DIR:-$HOME/robotapp}"
24
+
25
+ echo "🎮 Pika Mini-Game Builder"
26
+ echo "========================="
27
+ echo "Project: ${PROJECT_NAME}"
28
+ echo "Platform: ${PLATFORM}"
29
+ echo "Host dir: ${PIKA_HOST_DIR}"
30
+ echo ""
31
+
32
+ # Verify host directory exists
33
+ if [ ! -d "${PIKA_HOST_DIR}/node_modules/@callstack/repack" ]; then
34
+ echo "❌ Error: Pika host not found at ${PIKA_HOST_DIR}"
35
+ echo ""
36
+ echo "Please either:"
37
+ echo " 1. Set PIKA_HOST_DIR environment variable to your robotapp location"
38
+ echo " 2. Or clone robotapp to ~/robotapp and run 'npm install'"
39
+ echo ""
40
+ echo "Example:"
41
+ echo " export PIKA_HOST_DIR=/path/to/robotapp"
42
+ echo " ./scripts/pika-build.sh ios"
43
+ exit 1
44
+ fi
45
+
46
+ # Create workspace in host's mini-games folder (temporarily)
47
+ WORKSPACE_DIR="${PIKA_HOST_DIR}/mini-games/_build_${PROJECT_NAME}"
48
+
49
+ echo "📁 Setting up build workspace..."
50
+ rm -rf "${WORKSPACE_DIR}"
51
+ mkdir -p "${WORKSPACE_DIR}"
52
+
53
+ # Copy source files
54
+ cp -r "${PROJECT_DIR}/src" "${WORKSPACE_DIR}/"
55
+ cp "${PROJECT_DIR}/index.js" "${WORKSPACE_DIR}/"
56
+ cp "${PROJECT_DIR}/app.json" "${WORKSPACE_DIR}/"
57
+ cp "${PROJECT_DIR}/babel.config.js" "${WORKSPACE_DIR}/"
58
+ cp "${PROJECT_DIR}/rspack.config.mjs" "${WORKSPACE_DIR}/"
59
+ cp "${PROJECT_DIR}/tsconfig.json" "${WORKSPACE_DIR}/" 2>/dev/null || true
60
+
61
+ # Create react-native.config.js
62
+ cat > "${WORKSPACE_DIR}/react-native.config.js" << 'EOF'
63
+ module.exports = {
64
+ commands: require('@callstack/repack/commands/rspack'),
65
+ };
66
+ EOF
67
+
68
+ # Create package.json with peerDependencies
69
+ cat > "${WORKSPACE_DIR}/package.json" << EOF
70
+ {
71
+ "name": "${PROJECT_NAME}",
72
+ "version": "1.0.0",
73
+ "private": true,
74
+ "scripts": {
75
+ "build:ios": "npx react-native webpack-bundle --platform ios --entry-file index.js --dev false --bundle-output build/outputs/ios/local/index.ios.bundle --assets-dest build/outputs/ios/local",
76
+ "build:android": "npx react-native webpack-bundle --platform android --entry-file index.js --dev false --bundle-output build/outputs/android/local/index.android.bundle --assets-dest build/outputs/android/local"
77
+ },
78
+ "peerDependencies": {
79
+ "react": "18.3.1",
80
+ "react-native": "0.77.0"
81
+ }
82
+ }
83
+ EOF
84
+
85
+ echo "🔨 Building for ${PLATFORM}..."
86
+
87
+ cd "${WORKSPACE_DIR}"
88
+
89
+ # Set public path if MF_PUBLIC_PATH is set
90
+ if [ -n "$MF_PUBLIC_PATH" ]; then
91
+ export MF_PUBLIC_PATH
92
+ fi
93
+
94
+ npm run build:${PLATFORM}
95
+
96
+ echo "📁 Copying build output..."
97
+ mkdir -p "${PROJECT_DIR}/build/outputs/${PLATFORM}"
98
+ cp -r "${WORKSPACE_DIR}/build/outputs/${PLATFORM}/remotes" "${PROJECT_DIR}/build/outputs/${PLATFORM}/"
99
+
100
+ # Cleanup workspace
101
+ rm -rf "${WORKSPACE_DIR}"
102
+
103
+ echo ""
104
+ echo "✅ Build successful!"
105
+ echo ""
106
+ echo "Output: ${PROJECT_DIR}/build/outputs/${PLATFORM}/remotes/"
107
+ echo ""
108
+ echo "Container size:"
109
+ ls -lh "${PROJECT_DIR}/build/outputs/${PLATFORM}/remotes/"*container*.bundle 2>/dev/null || echo " (no container found)"
110
+ echo ""
111
+ echo "To test locally:"
112
+ echo " npx serve build/outputs/${PLATFORM}/remotes -l 9000 --cors"