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

feat: add --root cli option and make basic js api work #453

Merged
merged 4 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
22 changes: 0 additions & 22 deletions packages/core/src/build.ts

This file was deleted.

26 changes: 26 additions & 0 deletions packages/core/src/cli/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { type RsbuildInstance, createRsbuild } from '@rsbuild/core';
import { composeRsbuildEnvironments, pruneEnvironments } from '../config';
import type { RslibConfig } from '../types/config';
import { getAbsolutePath } from '../utils/helper';
import type { BuildOptions } from './commands';

export async function build(
config: RslibConfig,
options: Pick<BuildOptions, 'root' | 'lib' | 'watch'> = {},
): Promise<RsbuildInstance> {
const cwd = process.cwd();
const root = options.root ? getAbsolutePath(cwd, options.root) : cwd;

const environments = await composeRsbuildEnvironments(config, root);
const rsbuildInstance = await createRsbuild({
rsbuildConfig: {
environments: pruneEnvironments(environments, options.lib),
},
});

await rsbuildInstance.build({
watch: options.watch,
});

return rsbuildInstance;
}
57 changes: 26 additions & 31 deletions packages/core/src/cli/commands.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { type RsbuildMode, createRsbuild } from '@rsbuild/core';
import type { RsbuildMode } from '@rsbuild/core';
import { type Command, program } from 'commander';
import { build } from '../build';
import {
composeRsbuildEnvironments,
loadConfig,
pruneEnvironments,
} from '../config';
import { startMFDevServer } from '../mf';
import { logger } from '../utils/logger';
import { build } from './build';
import { getRslibConfig } from './init';
import { inspect } from './inspect';
import { startMFDevServer } from './mf';

export type CommonOptions = {
root?: string;
config?: string;
envMode?: string;
lib?: string[];
Expand All @@ -20,8 +18,8 @@ export type BuildOptions = CommonOptions & {
};

export type InspectOptions = CommonOptions & {
mode: RsbuildMode;
output: string;
mode?: RsbuildMode;
output?: string;
verbose?: boolean;
};

Expand All @@ -31,6 +29,10 @@ const applyCommonOptions = (command: Command) => {
'-c --config <config>',
'specify the configuration file, can be a relative or absolute path',
)
.option(
'-r --root <root>',
'specify the project root directory, can be an absolute path or a path relative to cwd',
)
.option(
'--env-mode <mode>',
'specify the env mode to load the `.env.[mode]` file',
Expand Down Expand Up @@ -60,11 +62,12 @@ export function runCli(): void {
.description('build the library for production')
.action(async (options: BuildOptions) => {
try {
const rslibConfig = await loadConfig({
path: options.config,
envMode: options.envMode,
const { root, rslibConfig } = await getRslibConfig(options);
await build(rslibConfig, {
root,
lib: options.lib,
watch: options.watch,
});
await build(rslibConfig, options);
} catch (err) {
logger.error('Failed to build.');
logger.error(err);
Expand All @@ -88,21 +91,13 @@ export function runCli(): void {
.action(async (options: InspectOptions) => {
try {
// TODO: inspect should output Rslib's config
const rslibConfig = await loadConfig({
path: options.config,
envMode: options.envMode,
});
const environments = await composeRsbuildEnvironments(rslibConfig);
const rsbuildInstance = await createRsbuild({
rsbuildConfig: {
environments: pruneEnvironments(environments, options.lib),
},
});
await rsbuildInstance.inspectConfig({
const { root, rslibConfig } = await getRslibConfig(options);
await inspect(rslibConfig, {
Timeless0911 marked this conversation as resolved.
Show resolved Hide resolved
root,
lib: options.lib,
mode: options.mode,
output: options.output,
verbose: options.verbose,
outputPath: options.output,
writeToDisk: true,
});
} catch (err) {
logger.error('Failed to inspect config.');
Expand All @@ -115,11 +110,11 @@ export function runCli(): void {
.description('start Rsbuild dev server of Module Federation format')
.action(async (options: CommonOptions) => {
try {
const rslibConfig = await loadConfig({
path: options.config,
envMode: options.envMode,
const { root, rslibConfig } = await getRslibConfig(options);
// TODO: support lib option in mf dev server
await startMFDevServer(rslibConfig, {
root,
});
await startMFDevServer(rslibConfig);
} catch (err) {
logger.error('Failed to start mf dev.');
logger.error(err);
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/cli/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { loadConfig } from '../config';
import type { RslibConfig } from '../types';
import { getAbsolutePath } from '../utils/helper';
import type { CommonOptions } from './commands';

export async function getRslibConfig(
options: CommonOptions,
): Promise<{ root: string; rslibConfig: RslibConfig }> {
const cwd = process.cwd();
const root = options.root ? getAbsolutePath(cwd, options.root) : cwd;
fi3ework marked this conversation as resolved.
Show resolved Hide resolved

const rslibConfig = await loadConfig({
cwd: root,
path: options.config,
envMode: options.envMode,
});

return { root, rslibConfig };
}
32 changes: 32 additions & 0 deletions packages/core/src/cli/inspect.ts
Timeless0911 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { type RsbuildInstance, createRsbuild } from '@rsbuild/core';
import { composeRsbuildEnvironments, pruneEnvironments } from '../config';
import type { RslibConfig } from '../types/config';
import { getAbsolutePath } from '../utils/helper';
import type { InspectOptions } from './commands';

export async function inspect(
config: RslibConfig,
options: Pick<
InspectOptions,
'root' | 'lib' | 'mode' | 'output' | 'verbose'
> = {},
): Promise<RsbuildInstance> {
const cwd = process.cwd();
const root = options.root ? getAbsolutePath(cwd, options.root) : cwd;

const environments = await composeRsbuildEnvironments(config, root);
const rsbuildInstance = await createRsbuild({
rsbuildConfig: {
environments: pruneEnvironments(environments, options.lib),
},
});

await rsbuildInstance.inspectConfig({
mode: options.mode,
verbose: options.verbose,
outputPath: options.output,
writeToDisk: true,
});

return rsbuildInstance;
}
18 changes: 13 additions & 5 deletions packages/core/src/mf.ts → packages/core/src/cli/mf.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import { createRsbuild, mergeRsbuildConfig } from '@rsbuild/core';
import { composeCreateRsbuildConfig } from './config';

import type { RsbuildConfig, RsbuildInstance } from '@rsbuild/core';
import type { RslibConfig } from './types';
import { composeCreateRsbuildConfig } from '../config';
import type { RslibConfig } from '../types';
import { getAbsolutePath } from '../utils/helper';
import type { CommonOptions } from './commands';

export async function startMFDevServer(
config: RslibConfig,
options: Pick<CommonOptions, 'root'> = {},
): Promise<RsbuildInstance | undefined> {
const rsbuildInstance = await initMFRsbuild(config);
const cwd = process.cwd();
const root = options.root ? getAbsolutePath(cwd, options.root) : cwd;
const rsbuildInstance = await initMFRsbuild(config, root);
return rsbuildInstance;
}

async function initMFRsbuild(
rslibConfig: RslibConfig,
root: string,
): Promise<RsbuildInstance | undefined> {
const rsbuildConfigObject = await composeCreateRsbuildConfig(rslibConfig);
const rsbuildConfigObject = await composeCreateRsbuildConfig(
rslibConfig,
root,
);
const mfRsbuildConfig = rsbuildConfigObject.find(
(config) => config.format === 'mf',
);
Expand Down
21 changes: 8 additions & 13 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1084,12 +1084,11 @@ const composeExternalHelpersConfig = (
return defaultConfig;
};

async function composeLibRsbuildConfig(config: LibConfig, configPath: string) {
async function composeLibRsbuildConfig(config: LibConfig, root: string) {
checkMFPlugin(config);
const rootPath = dirname(configPath);
const pkgJson = readPackageJson(rootPath);
const pkgJson = readPackageJson(root);
const { compilerOptions } = await loadTsconfig(
rootPath,
root,
config.source?.tsconfigPath,
);
const cssModulesAuto = config.output?.cssModules?.auto ?? true;
Expand Down Expand Up @@ -1148,7 +1147,7 @@ async function composeLibRsbuildConfig(config: LibConfig, configPath: string) {
const { entryConfig, lcp } = await composeEntryConfig(
config.source?.entry,
config.bundle,
dirname(configPath),
root,
cssModulesAuto,
);
const cssConfig = composeCssConfig(lcp, config.bundle);
Expand Down Expand Up @@ -1192,10 +1191,9 @@ async function composeLibRsbuildConfig(config: LibConfig, configPath: string) {

export async function composeCreateRsbuildConfig(
rslibConfig: RslibConfig,
path?: string,
root: string,
): Promise<RsbuildConfigWithLibInfo[]> {
const constantRsbuildConfig = await createConstantRsbuildConfig();
const configPath = path ?? rslibConfig._privateMeta?.configFilePath!;
const { lib: libConfigsArray, ...sharedRsbuildConfig } = rslibConfig;

if (!libConfigsArray) {
Expand All @@ -1212,10 +1210,7 @@ export async function composeCreateRsbuildConfig(

// Merge the configuration of each environment based on the shared Rsbuild
// configuration and Lib configuration in the settings.
const libRsbuildConfig = await composeLibRsbuildConfig(
userConfig,
configPath,
);
const libRsbuildConfig = await composeLibRsbuildConfig(userConfig, root);

// Reset certain fields because they will be completely overridden by the upcoming merge.
// We don't want to retain them in the final configuration.
Expand Down Expand Up @@ -1271,11 +1266,11 @@ export async function composeCreateRsbuildConfig(

export async function composeRsbuildEnvironments(
rslibConfig: RslibConfig,
path?: string,
root: string,
): Promise<Record<string, EnvironmentConfig>> {
const rsbuildConfigWithLibInfo = await composeCreateRsbuildConfig(
rslibConfig,
path,
root,
);

// User provided ids should take precedence over generated ids.
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
export { prepareCli } from './cli/prepare';
export { runCli } from './cli/commands';
export { build } from './cli/build';
export { inspect } from './cli/inspect';
export { startMFDevServer } from './cli/mf';
export {
defineConfig,
loadConfig,
composeCreateRsbuildConfig as unstable_composeCreateRsbuildConfig,
} from './config';
export { build } from './build';
export { logger } from './utils/logger';
export type * from './types';

Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/utils/helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fs from 'node:fs';
import fsP from 'node:fs/promises';
import path from 'node:path';
import path, { isAbsolute, join } from 'node:path';
import type { RsbuildPlugins } from '@rsbuild/core';
import color from 'picocolors';

Expand Down Expand Up @@ -109,6 +109,10 @@ export async function calcLongestCommonPath(
return lca;
}

export function getAbsolutePath(base: string, filepath: string): string {
return isAbsolute(filepath) ? filepath : join(base, filepath);
}

export const readPackageJson = (rootPath: string): undefined | PkgJson => {
const pkgJsonPath = path.join(rootPath, './package.json');

Expand Down
2 changes: 1 addition & 1 deletion packages/core/tests/__snapshots__/config.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ exports[`Should compose create Rsbuild config correctly > Merge Rsbuild config 1
"pnpapi",
],
"filename": {
"js": "[name].js",
"js": "[name].mjs",
Timeless0911 marked this conversation as resolved.
Show resolved Hide resolved
},
"filenameHash": false,
"minify": {
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions tests/integration/cli/build.test.ts
Timeless0911 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,40 @@ describe('build command', async () => {
]
`);
});

test('--config', async () => {
await fse.remove(path.join(__dirname, 'dist'));
execSync(
'npx rslib build --config ./custom-config/rslib.config.custom.ts',
{
cwd: __dirname,
},
);

const files = await globContentJSON(path.join(__dirname, 'dist'));
const fileNames = Object.keys(files).sort();
expect(fileNames).toMatchInlineSnapshot(`
[
"<ROOT>/tests/integration/cli/dist/custom/index.cjs",
"<ROOT>/tests/integration/cli/dist/custom/index.js",
]
`);
});

test('--root', async () => {
await fse.remove(path.join(__dirname, 'dist'));
console.log('__dirname: ', __dirname);
execSync('npx rslib build --root custom-root', {
cwd: __dirname,
});

const files = await globContentJSON(path.join(__dirname, 'dist'));
const fileNames = Object.keys(files).sort();
expect(fileNames).toMatchInlineSnapshot(`
[
"<ROOT>/tests/integration/cli/dist/root/index.cjs",
"<ROOT>/tests/integration/cli/dist/root/index.js",
]
`);
});
});
Loading
Loading