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
2 changes: 1 addition & 1 deletion e2e/cases/hmr/reconnect/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { expect, rspackTest } from '@e2e/helper';
const cwd = __dirname;

rspackTest(
'should reconnect Web Socket server as expected',
'should reconnect WebSocket server as expected',
async ({ page, dev, devOnly, editFile }) => {
await fs.promises.cp(join(cwd, 'src'), join(cwd, 'test-temp-src'), {
recursive: true,
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/cli/init.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'node:path';
import { createRsbuild } from '../createRsbuild';
import { castArray, ensureAbsolutePath } from '../helpers';
import { castArray } from '../helpers';
import { ensureAbsolutePath } from '../helpers/path';
import { loadConfig as baseLoadConfig } from '../loadConfig';
import { logger } from '../logger';
import { watchFilesForRestart } from '../restart';
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/createRsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
castArray,
color,
getNodeEnv,
isEmptyDir,
isFunction,
pick,
setNodeEnv,
} from './helpers';
import { isEmptyDir } from './helpers/fs';
import { initPluginAPI } from './initPlugins';
import { type LoadEnvResult, loadEnv } from './loadEnv';
import { isDebug, logger } from './logger';
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
TS_CONFIG_FILE,
WASM_DIST_DIR,
} from './constants';
import { findExists, getNodeEnv, isFileExists } from './helpers';
import { getNodeEnv } from './helpers';
import { findExists, isFileExists } from './helpers/fs';
import { mergeRsbuildConfig } from './mergeConfig';
import type {
NormalizedConfig,
Expand Down
45 changes: 45 additions & 0 deletions packages/core/src/helpers/compiler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { DEFAULT_ASSET_PREFIX } from '../constants';
import type { Rspack } from '../types';

export const isMultiCompiler = (
compiler: Rspack.Compiler | Rspack.MultiCompiler,
): compiler is Rspack.MultiCompiler => {
return 'compilers' in compiler && Array.isArray(compiler.compilers);
};

export const getPublicPathFromCompiler = (
compiler: Rspack.Compiler | Rspack.Compilation,
): string => {
const { publicPath } = compiler.options.output;

if (typeof publicPath === 'string') {
// 'auto' is a magic value in Rspack and behave like `publicPath: ""`
if (publicPath === 'auto') {
return '';
}
return publicPath.endsWith('/') ? publicPath : `${publicPath}/`;
}

// publicPath function is not supported yet, fallback to default value
return DEFAULT_ASSET_PREFIX;
};

export const applyToCompiler = (
compiler: Rspack.Compiler | Rspack.MultiCompiler,
apply: (c: Rspack.Compiler, index: number) => void,
): void => {
if (isMultiCompiler(compiler)) {
compiler.compilers.forEach(apply);
} else {
apply(compiler, 0);
}
};

export const addCompilationError = (
compilation: Rspack.Compilation,
message: string,
): void => {
compilation.errors.push(
new compilation.compiler.webpack.WebpackError(message),
);
};
185 changes: 1 addition & 184 deletions packages/core/src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { posix } from 'node:path';
import { URL } from 'node:url';
import deepmerge from 'deepmerge';
import RspackChain from '../../compiled/rspack-chain';
import { DEFAULT_ASSET_PREFIX } from '../constants';
import type {
FilenameConfig,
NormalizedConfig,
Expand All @@ -12,14 +9,7 @@ import type {
} from '../types';
import { color } from './vendors';

export * from './fs';
export * from './path';
export * from './stats';
export * from './vendors';
export { RspackChain };

// Lazy compilation was stabilized in Rspack v1.5.0
export const rspackMinVersion = '1.5.0';
export { color, RspackChain };

export const getNodeEnv = (): string => process.env.NODE_ENV || '';
export const setNodeEnv = (env: string): void => {
Expand Down Expand Up @@ -59,149 +49,6 @@ export const cloneDeep = <T>(value: T): T => {
});
};

const compareSemver = (version1: string, version2: string) => {
const parts1 = version1.split('.').map(Number);
const parts2 = version2.split('.').map(Number);
const len = Math.max(parts1.length, parts2.length);

for (let i = 0; i < len; i++) {
const item1 = parts1[i] ?? 0;
const item2 = parts2[i] ?? 0;
if (item1 > item2) {
return 1;
}
if (item1 < item2) {
return -1;
}
}

return 0;
};

/**
* If the application overrides the Rspack version to a lower one,
* we should check that the Rspack version is greater than the minimum
* supported version.
*/
export const isSatisfyRspackVersion = (originalVersion: string): boolean => {
let version = originalVersion;

// The nightly version of Rspack is to append `-canary-abc` to the current version
if (version.includes('-canary')) {
version = version.split('-canary')[0];
}

if (version && /^[\d.]+$/.test(version)) {
return compareSemver(version, rspackMinVersion) >= 0;
}

// ignore other unstable versions
return true;
};

export const removeLeadingSlash = (s: string): string => s.replace(/^\/+/, '');
export const removeTailingSlash = (s: string): string => s.replace(/\/+$/, '');
export const addTrailingSlash = (s: string): string =>
s.endsWith('/') ? s : `${s}/`;

export const formatPublicPath = (
publicPath: string,
withSlash = true,
): string => {
// 'auto' is a magic value in Rspack and we should not add trailing slash
if (publicPath === 'auto') {
return publicPath;
}

return withSlash
? addTrailingSlash(publicPath)
: removeTailingSlash(publicPath);
};

export const getPublicPathFromChain = (
chain: RspackChain,
withSlash = true,
): string => {
const publicPath: Rspack.PublicPath = chain.output.get('publicPath');

if (typeof publicPath === 'string') {
return formatPublicPath(publicPath, withSlash);
}

return formatPublicPath(DEFAULT_ASSET_PREFIX, withSlash);
};

export const getPublicPathFromCompiler = (
compiler: Rspack.Compiler | Rspack.Compilation,
): string => {
const { publicPath } = compiler.options.output;

if (typeof publicPath === 'string') {
// 'auto' is a magic value in Rspack and behave like `publicPath: ""`
if (publicPath === 'auto') {
return '';
}
return publicPath.endsWith('/') ? publicPath : `${publicPath}/`;
}

// publicPath function is not supported yet, fallback to default value
return DEFAULT_ASSET_PREFIX;
};

export const urlJoin = (base: string, path: string) => {
const [urlProtocol, baseUrl] = base.split('://');
return `${urlProtocol}://${posix.join(baseUrl, path)}`;
};

// Can be replaced with URL.canParse when we drop support for Node.js 18
export const canParse = (url: string): boolean => {
try {
new URL(url);
return true;
} catch {
return false;
}
};

export const ensureAssetPrefix = (
url: string,
assetPrefix: Rspack.PublicPath = DEFAULT_ASSET_PREFIX,
): string => {
// The use of an absolute URL without a protocol is technically legal,
// however it cannot be parsed as a URL instance, just return it.
// e.g. str is //example.com/foo.js
if (url.startsWith('//')) {
return url;
}

// If str is an complete URL, just return it.
// Only absolute url with hostname & protocol can be parsed into URL instance.
// e.g. str is https://example.com/foo.js
if (canParse(url)) {
return url;
}

// 'auto' is a magic value in Rspack and behave like `publicPath: ""`
if (assetPrefix === 'auto') {
return url;
}

// function is not supported by this helper
if (typeof assetPrefix === 'function') {
return url;
}

if (assetPrefix.startsWith('http')) {
return urlJoin(assetPrefix, url);
}

if (assetPrefix.startsWith('//')) {
return urlJoin(`https:${assetPrefix}`, url).replace('https:', '');
}

return posix.join(assetPrefix, url);
};

export function getFilename(
config: NormalizedConfig | NormalizedEnvironmentConfig,
type: 'js',
Expand Down Expand Up @@ -299,24 +146,9 @@ export function partition<T>(
return [truthy, falsy];
}

export const applyToCompiler = (
compiler: Rspack.Compiler | Rspack.MultiCompiler,
apply: (c: Rspack.Compiler, index: number) => void,
): void => {
if (isMultiCompiler(compiler)) {
compiler.compilers.forEach(apply);
} else {
apply(compiler, 0);
}
};

export const upperFirst = (str: string): string =>
str ? str.charAt(0).toUpperCase() + str.slice(1) : '';

// Determine if the string is a URL
export const isURL = (str: string): boolean =>
str.startsWith('http') || str.startsWith('//:');

export const createVirtualModule = (content: string) =>
`data:text/javascript,${content}`;

Expand All @@ -325,12 +157,6 @@ export function isWebTarget(target: RsbuildTarget | RsbuildTarget[]): boolean {
return targets.includes('web') || targets.includes('web-worker');
}

export const isMultiCompiler = (
compiler: Rspack.Compiler | Rspack.MultiCompiler,
): compiler is Rspack.MultiCompiler => {
return 'compilers' in compiler && Array.isArray(compiler.compilers);
};

export function pick<T, U extends keyof T>(
obj: T,
keys: readonly U[],
Expand Down Expand Up @@ -384,15 +210,6 @@ export const isTTY = (type: 'stdin' | 'stdout' = 'stdout'): boolean => {
);
};

export const addCompilationError = (
compilation: Rspack.Compilation,
message: string,
): void => {
compilation.errors.push(
new compilation.compiler.webpack.WebpackError(message),
);
};

export async function hash(data: string): Promise<string> {
const crypto = await import('node:crypto');
// Available in Node.js v20.12.0
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/helpers/stats.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { logger } from '../logger';
import type { ActionType, RsbuildStats, Rspack } from '../types';
import { isMultiCompiler } from './';
import { isMultiCompiler } from './compiler';
import { formatStatsError } from './format';
import { color } from './vendors';

Expand Down
Loading
Loading