Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/expo-go/ios/Exponent/Supporting/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>55.0.4</string>
<string>55.0.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand Down Expand Up @@ -61,7 +61,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>55.0.4</string>
<string>55.0.5</string>
<key>FacebookAdvertiserIDCollectionEnabled</key>
<false/>
<key>FacebookAppID</key>
Expand Down
2 changes: 2 additions & 0 deletions packages/@expo/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

### 🎉 New features

- Add `--source-maps inline` option to `expo export` for embedding source maps in JavaScript bundles. ([#42492](https://github.com/expo/expo/pull/42492) by [@brentvatne](https://github.com/brentvatne))

### 🐛 Bug fixes

### 💡 Others
Expand Down
2 changes: 1 addition & 1 deletion packages/@expo/cli/e2e/__tests__/export.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ it('runs `npx expo export --help`', async () => {
--dump-assetmap Emit an asset map for further processing
--no-ssg, --api-only Skip exporting static HTML files and only export API routes for web
-p, --platform <platform> Options: android, ios, web, all. Default: all
-s, --source-maps Emit JavaScript source maps
-s, --source-maps [mode] Emit JavaScript source maps. mode: external (when omitted), inline
-c, --clear Clear the bundler cache
-h, --help Usage info
"
Expand Down
26 changes: 25 additions & 1 deletion packages/@expo/cli/src/export/__tests__/resolveOptions-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe(resolveOptionsAsync, () => {
'--clear': true,
'--dev': true,
'--dump-assetmap': true,
'--source-maps': true,
'--source-maps': 'true',
'--max-workers': 2,
})
).resolves.toEqual({
Expand All @@ -74,13 +74,36 @@ describe(resolveOptionsAsync, () => {
dumpAssetmap: true,
hostedNative: false,
sourceMaps: true,
inlineSourceMaps: false,
maxWorkers: 2,
skipSSG: false,
outputDir: 'foobar',
platforms: ['android'],
});
});

it(`parses inline source maps option`, async () => {
await expect(
resolveOptionsAsync('/', {
'--source-maps': 'inline',
})
).resolves.toMatchObject({
sourceMaps: true,
inlineSourceMaps: true,
});
});

it(`parses source maps option as boolean true`, async () => {
await expect(
resolveOptionsAsync('/', {
'--source-maps': true,
})
).resolves.toMatchObject({
sourceMaps: true,
inlineSourceMaps: false,
});
});

it(`parses default options`, async () => {
await expect(resolveOptionsAsync('/', {})).resolves.toEqual({
clear: false,
Expand All @@ -90,6 +113,7 @@ describe(resolveOptionsAsync, () => {
dumpAssetmap: false,
hostedNative: false,
sourceMaps: false,
inlineSourceMaps: false,
maxWorkers: undefined,
skipSSG: false,
outputDir: 'dist',
Expand Down
5 changes: 4 additions & 1 deletion packages/@expo/cli/src/export/exportApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export async function exportAppAsync(
dev,
dumpAssetmap,
sourceMaps,
inlineSourceMaps,
minify,
bytecode,
maxWorkers,
Expand All @@ -63,6 +64,7 @@ export async function exportAppAsync(
Options,
| 'dumpAssetmap'
| 'sourceMaps'
| 'inlineSourceMaps'
| 'dev'
| 'clear'
| 'outputDir'
Expand Down Expand Up @@ -196,7 +198,8 @@ export async function exportAppAsync(
}),
mode: dev ? 'development' : 'production',
engine: isHermes ? 'hermes' : undefined,
serializerIncludeMaps: sourceMaps,
serializerIncludeMaps: sourceMaps || inlineSourceMaps,
inlineSourceMap: inlineSourceMaps,
bytecode: bytecode && isHermes,
reactCompiler: !!exp.experiments?.reactCompiler,
hosted: hostedNative,
Expand Down
85 changes: 48 additions & 37 deletions packages/@expo/cli/src/export/index.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,46 @@
#!/usr/bin/env node
import arg from 'arg';
import chalk from 'chalk';
import path from 'path';

import { Command } from '../../bin/cli';
import { assertArgs, getProjectRoot, printHelp } from '../utils/args';
import { assertWithOptionsArgs, printHelp } from '../utils/args';
import { logCmdError } from '../utils/errors';

export const expoExport: Command = async (argv) => {
const args = assertArgs(
{
// Types
'--help': Boolean,
'--clear': Boolean,
'--dump-assetmap': Boolean,
'--dev': Boolean,
'--source-maps': Boolean,
'--max-workers': Number,
'--output-dir': String,
'--platform': [String],
'--no-minify': Boolean,
'--no-bytecode': Boolean,
'--no-ssg': Boolean,
'--api-only': Boolean,
'--unstable-hosted-native': Boolean,
const rawArgsMap: arg.Spec = {
// Types
'--help': Boolean,
'--clear': Boolean,
'--dump-assetmap': Boolean,
'--dev': Boolean,
'--max-workers': Number,
'--output-dir': String,
'--platform': [String],
'--no-minify': Boolean,
'--no-bytecode': Boolean,
'--no-ssg': Boolean,
'--api-only': Boolean,
'--unstable-hosted-native': Boolean,

// Hack: This is added because EAS CLI always includes the flag.
// If supplied, we'll do nothing with the value, but at least the process won't crash.
// Note that we also don't show this value in the `--help` prompt since we don't want people to use it.
'--experimental-bundle': Boolean,
// Hack: This is added because EAS CLI always includes the flag.
// If supplied, we'll do nothing with the value, but at least the process won't crash.
// Note that we also don't show this value in the `--help` prompt since we don't want people to use it.
'--experimental-bundle': Boolean,

// Aliases
'-h': '--help',
'-s': '--source-maps',
// '-d': '--dump-assetmap',
'-c': '--clear',
'-p': '--platform',
// Interop with Metro docs and RedBox errors.
'--reset-cache': '--clear',
// Aliases
'-h': '--help',
// '-d': '--dump-assetmap',
'-c': '--clear',
'-p': '--platform',
// Interop with Metro docs and RedBox errors.
'--reset-cache': '--clear',
};

// Deprecated
'--dump-sourcemap': '--source-maps',
},
argv
);
const args = assertWithOptionsArgs(rawArgsMap, {
argv,
permissive: true,
});

if (args['--help']) {
printHelp(
Expand All @@ -57,16 +56,28 @@ export const expoExport: Command = async (argv) => {
`--dump-assetmap Emit an asset map for further processing`,
`--no-ssg, --api-only Skip exporting static HTML files and only export API routes for web`,
chalk`-p, --platform <platform> Options: android, ios, web, all. {dim Default: all}`,
`-s, --source-maps Emit JavaScript source maps`,
chalk`-s, --source-maps [mode] Emit JavaScript source maps. {dim mode: external (when omitted), inline}`,
`-c, --clear Clear the bundler cache`,
`-h, --help Usage info`,
].join('\n')
);
}

const projectRoot = getProjectRoot(args);
// Handle --source-maps which can be a string or boolean (e.g., --source-maps or --source-maps inline)
const { resolveStringOrBooleanArgsAsync } = await import('../utils/resolveArgs.js');
const parsed = await resolveStringOrBooleanArgsAsync(argv ?? [], rawArgsMap, {
'--source-maps': Boolean,
'-s': '--source-maps',
// Deprecated
'--dump-sourcemap': '--source-maps',
}).catch(logCmdError);

const projectRoot = path.resolve(parsed.projectRoot);
const { resolveOptionsAsync } = await import('./resolveOptions.js');
const options = await resolveOptionsAsync(projectRoot, args).catch(logCmdError);
const options = await resolveOptionsAsync(projectRoot, {
...args,
'--source-maps': parsed.args['--source-maps'],
}).catch(logCmdError);

const { exportAsync } = await import('./exportAsync.js');
return exportAsync(projectRoot, options).catch(logCmdError);
Expand Down
10 changes: 9 additions & 1 deletion packages/@expo/cli/src/export/resolveOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type Options = {
bytecode: boolean;
dumpAssetmap: boolean;
sourceMaps: boolean;
inlineSourceMaps: boolean;
skipSSG: boolean;
hostedNative: boolean;
};
Expand Down Expand Up @@ -81,6 +82,12 @@ export async function resolveOptionsAsync(projectRoot: string, args: any): Promi
const platformBundlers = getPlatformBundlers(projectRoot, exp);

const platforms = resolvePlatformOption(exp, platformBundlers, args['--platform']);

// --source-maps can be true, "external", or "inline"
const sourceMapsArg = args['--source-maps'];
const sourceMaps = !!sourceMapsArg;
const inlineSourceMaps = sourceMapsArg === 'inline';

return {
platforms,
hostedNative: !!args['--unstable-hosted-native'],
Expand All @@ -91,7 +98,8 @@ export async function resolveOptionsAsync(projectRoot: string, args: any): Promi
dev: !!args['--dev'],
maxWorkers: args['--max-workers'],
dumpAssetmap: !!args['--dump-assetmap'],
sourceMaps: !!args['--source-maps'],
sourceMaps,
inlineSourceMaps,
skipSSG: !!args['--no-ssg'] || !!args['--api-only'],
};
}
87 changes: 87 additions & 0 deletions packages/@expo/cli/src/utils/__tests__/resolveArgs-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ describe(collapseAliases, () => {
const actual = collapseAliases(arg, args);
expect(actual).toEqual(['--basic', '--help']);
});

it(`will collapse all occurrences of an alias`, () => {
const arg = {
'--platform': [String],
'-p': '--platform',
};
const args = ['-p', 'web', '-p', 'ios'];
const actual = collapseAliases(arg, args);
expect(actual).toEqual(['--platform', 'web', '--platform', 'ios']);
});
});

describe(_resolveStringOrBooleanArgs, () => {
Expand Down Expand Up @@ -133,6 +143,73 @@ describe(resolveStringOrBooleanArgsAsync, () => {
projectRoot: 'custom-root',
});
});

it(`handles array-type arguments in rawMap`, async () => {
// This simulates `expo export -p web -p ios --source-maps`
// Array-type args like --platform should be filtered out and not cause errors
await expect(
resolveStringOrBooleanArgsAsync(
['-p', 'web', '-p', 'ios', '--source-maps'],
{
'--platform': [String],
'-p': '--platform',
},
{
'--source-maps': Boolean,
}
)
).resolves.toEqual({
args: {
'--source-maps': true,
},
projectRoot: '.',
});
});

it(`handles array-type arguments with extra args value`, async () => {
// This simulates `expo export -p web -p ios --source-maps inline`
await expect(
resolveStringOrBooleanArgsAsync(
['-p', 'web', '-p', 'ios', '--source-maps', 'inline', 'custom-root'],
{
'--platform': [String],
'-p': '--platform',
},
{
'--source-maps': Boolean,
}
)
).resolves.toEqual({
args: {
'--source-maps': 'inline',
},
projectRoot: 'custom-root',
});
});

it(`treats value after string-or-boolean flag as the flag value, not project root`, async () => {
// This documents a limitation: `--source-maps custom-root` treats `custom-root`
// as the value for --source-maps, not as the project root.
// To use a project root with --source-maps as boolean, put it before the flag
// or use an explicit value like `--source-maps inline custom-root`.
await expect(
resolveStringOrBooleanArgsAsync(
['-p', 'web', '--source-maps', 'custom-root'],
{
'--platform': [String],
'-p': '--platform',
},
{
'--source-maps': Boolean,
}
)
).resolves.toEqual({
args: {
'--source-maps': 'custom-root', // NOT true
},
projectRoot: '.', // NOT 'custom-root'
});
});
});

describe(assertDuplicateArgs, () => {
Expand All @@ -145,4 +222,14 @@ describe(assertDuplicateArgs, () => {
assertDuplicateArgs(['--device', '--bar', '--device'], [['--device', '-d']])
).toThrowErrorMatchingInlineSnapshot(`"Can only provide one instance of --device or -d"`);
});
it(`does not assert for array-type arguments`, () => {
const spec = {
'--platform': [String],
'-p': '--platform',
};
// Multiple --platform flags should be allowed when it's an array type
expect(() =>
assertDuplicateArgs(['--platform', 'web', '--platform', 'ios'], [['-p', '--platform']], spec)
).not.toThrow();
});
});
4 changes: 4 additions & 0 deletions packages/@expo/cli/src/utils/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export function replaceValue<T>(values: T[], original: T, replacement: T): T[] {
return values;
}

export function replaceAllValues<T>(values: T[], original: T, replacement: T): T[] {
return values.map((value) => (value === original ? replacement : value));
}

/** lodash.uniqBy */
export function uniqBy<T>(array: T[], key: (item: T) => string): T[] {
const seen: { [key: string]: boolean } = {};
Expand Down
Loading
Loading