Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] feat: CLI #762

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
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
33 changes: 33 additions & 0 deletions packages/commands-rspack/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@callstack/repack-commands-rspack",
"description": "Re.Pack CLI commands that use Rspack as the bundler",
"author": "Jakub Romańczyk <jakub.romanczyk@callstack.com>",
"license": "MIT",
"version": "5.0.0-alpha.0",
"homepage": "https://github.com/callstack/repack",
"repository": "github:callstack/repack",
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"main": "dist/index.js",
"engineStrict": true,
"engines": {
"node": ">=18"
},
"type": "module",
"scripts": {
"build": "tsc",
"lint": "eslint --ext .ts src",
"typecheck": "tsc --noEmit"
},
"dependencies": {},
"devDependencies": {
"@types/dedent": "^0.7.2",
"@types/node": "18",
"@types/semver": "^7.5.6",
"@types/yargs": "^17.0.32",
"eslint": "^8.57.0",
"typescript": "^5.5.3"
}
}
59 changes: 59 additions & 0 deletions packages/commands-rspack/src/bundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { rspack } from '@rspack/core';
import type { Configuration, Stats } from '@rspack/core';
import { normalizeStatsOptions, writeStats } from '../common';

/**
* Bundle command for React Native Community CLI.
* It runs Rspack, builds bundle and saves it alongside any other assets and Source Map
* to filesystem.
*
* @param _ Original, non-parsed arguments that were provided when running this command.
* @param config React Native Community CLI configuration object.
* @param args Parsed command line arguments.
*
* @internal
* @category CLI command
*/
export async function bundle(config: Configuration) {
const errorHandler = async (error: Error | null, stats?: Stats) => {
if (error) {
console.error(error);
process.exit(2);
}

if (stats?.hasErrors()) {
stats.compilation?.errors?.forEach((e) => {
console.error(e);
});
process.exit(2);
}

if (args.json && stats !== undefined) {
const statsOptions = normalizeStatsOptions(
compiler.options.stats,
args.stats
);

const statsJson = stats.toJson(statsOptions);
await writeStats(statsJson, args.json);
}
};

const compiler = rspack(config);

return new Promise<void>((resolve) => {
if (args.watch) {
compiler.hooks.watchClose.tap('bundle', resolve);
compiler.watch(config.watchOptions ?? {}, errorHandler);
} else {
compiler.run((error, stats) => {
// make cache work: https://webpack.js.org/api/node/#run
compiler.close(async (closeErr) => {
if (closeErr) console.error(closeErr);
await errorHandler(error, stats);
resolve();
});
});
}
});
}
153 changes: 153 additions & 0 deletions packages/commands-rspack/src/start.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { URL } from 'node:url';
import { makeLogEntryFromFastifyLog } from '../../logging';
import { parseFileUrl, runAdbReverse, setupInteractions } from '../common';
import { DEFAULT_HOSTNAME, DEFAULT_PORT } from '../consts';
import type { StartArguments } from '../types';
import { Compiler } from './Compiler';

/**
* Start command for React Native Community CLI.
* It runs `@callstack/repack-dev-server` to provide Development Server functionality to React Native apps
* in development mode.
*
* @param _ Original, non-parsed arguments that were provided when running this command.
* @param config React Native Community CLI configuration object.
* @param args Parsed command line arguments.
*
* @internal
* @category CLI command
*/
export async function start(
_: string[],
// cliConfig: Config,
args: StartArguments
) {
// @ts-ignore
const compiler = new Compiler(cliOptions, reporter);

const { createServer } = await import('@callstack/repack-dev-server');
const { start, stop } = await createServer({
options: {
rootDir: cliOptions.config.root,
host: args.host || DEFAULT_HOSTNAME,
port: args.port ?? DEFAULT_PORT,
https: args.https
? {
cert: args.cert,
key: args.key,
}
: undefined,
logRequests: showHttpRequests,
},
experiments: {
experimentalDebugger: args.experimentalDebugger,
},
delegate: (ctx) => {
if (args.interactive) {
setupInteractions(
{
onReload: () => {
ctx.broadcastToMessageClients({ method: 'reload' });
},
onOpenDevMenu: () => {
ctx.broadcastToMessageClients({ method: 'devMenu' });
},
},
ctx.log
);
}

if (reversePort && args.port) {
void runAdbReverse(args.port, ctx.log);
}

compiler.setDevServerContext(ctx);

return {
compiler: {
getAsset: async (filename, platform) =>
(await compiler.getAsset(filename, platform)).data,
getMimeType: (filename) => compiler.getMimeType(filename),
inferPlatform: (uri) => {
const url = new URL(uri, 'protocol://domain');
if (!url.searchParams.get('platform')) {
const [, platform] = /^\/(.+)\/.+$/.exec(url.pathname) ?? [];
return platform;
}

return undefined;
},
},
symbolicator: {
getSource: (fileUrl) => {
const { filename, platform } = parseFileUrl(fileUrl);
return compiler.getSource(filename, platform);
},
getSourceMap: (fileUrl) => {
// TODO Align this with output.hotModuleUpdateChunkFilename
if (fileUrl.endsWith('.hot-update.js')) {
const { pathname } = new URL(fileUrl);
const [platform, filename] = pathname.split('/').filter(Boolean);
return compiler.getSourceMap(filename, platform);
}

const { filename, platform } = parseFileUrl(fileUrl);
if (!platform) {
throw new Error('Cannot infer platform for file URL');
}

return compiler.getSourceMap(filename, platform);
},
shouldIncludeFrame: (frame) => {
// If the frame points to internal bootstrap/module system logic, skip the code frame.
return !/webpack[/\\]runtime[/\\].+\s/.test(frame.file);
},
},
hmr: {
getUriPath: () => '/__hmr',
onClientConnected: (platform, clientId) => {
ctx.broadcastToHmrClients(
{ action: 'sync', body: compiler.getHmrBody(platform) },
platform,
[clientId]
);
},
},
messages: {
getHello: () => 'React Native packager is running',
getStatus: () => 'packager-status:running',
},
logger: {
onMessage: (log) => {
const logEntry = makeLogEntryFromFastifyLog(log);
logEntry.issuer = 'DevServer';
reporter.process(logEntry);
},
},
api: {
getPlatforms: () => Promise.resolve(compiler.platforms),
getAssets: (platform) =>
Promise.resolve(
Object.entries(compiler.assetsCache[platform] ?? {}).map(
([name, asset]) => ({ name, size: asset.size })
)
),
getCompilationStats: (platform) =>
Promise.resolve(compiler.statsCache[platform] ?? null),
},
};
},
});

await compiler.init();
await start();

compiler.start();

return {
stop: async () => {
reporter.stop();
await stop();
},
};
}
46 changes: 46 additions & 0 deletions packages/commands-shared/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@callstack/repack-commands-shared",
"description": "Shared utilites for @callstack/repack commands",
"author": "Jakub Romańczyk <jakub.romanczyk@callstack.com>",
"license": "MIT",
"version": "5.0.0-alpha.0",
"homepage": "https://github.com/callstack/repack",
"repository": "github:callstack/repack",
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"bin": "dist/bin.js",
"main": "dist/index.js",
"files": [
"dist",
"!*.d.ts",
"!*.map"
],
"engineStrict": true,
"engines": {
"node": ">=18"
},
"type": "module",
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@discoveryjs/json-ext": "^0.5.7",
"mime-types": "^2.1.35"
},
"devDependencies": {
"@microsoft/api-extractor": "^7.47.9",
"@rslib/core": "^0.0.8",
"@types/dedent": "^0.7.2",
"@types/mime-types": "^2.1.1",
"@types/node": "18",
"@types/semver": "^7.5.6",
"@types/yargs": "^17.0.32",
"execa": "^5.0.0",
"memfs": "^4.11.1",
"typescript": "^5.5.3",
"vitest": "^2.0.5"
}
}
20 changes: 20 additions & 0 deletions packages/commands-shared/rslib.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { defineConfig } from '@rslib/core';

export default defineConfig({
lib: [
{
dts: {
bundle: true,
},
format: 'esm',
source: {
tsconfigPath: 'tsconfig.build.json',
},
syntax: 'es2021',
},
],
output: {
target: 'node',
minify: false,
},
});
Loading
Loading