@modern-js/libuild
Version:
A tool for building modern JavaScript libraries
822 lines (725 loc) • 24 kB
TypeScript
/// <reference types="less" />
/// <reference types="node" />
import type { AcceptedPlugin } from 'postcss';
import type { BuildOptions } from 'esbuild';
import { Message as EsbuildError } from 'esbuild';
import { ImportKind } from 'esbuild';
import type { Loader as Loader_2 } from 'esbuild';
import type { Metafile } from 'esbuild';
import type { MinifyOptions } from 'terser';
import type { OnLoadArgs } from 'esbuild';
import type { OnLoadResult } from 'esbuild';
import type { OnResolveArgs } from 'esbuild';
import type { OnResolveResult } from 'esbuild';
import type { Plugin as Plugin_2 } from 'postcss';
import type { ProcessOptions } from 'postcss';
import type { Options as sassOptions } from 'sass';
declare type AdditionalData = string | ((filePath: string) => string);
declare type Append<T extends any[], U> = {
0: [U];
1: [T[0], U];
2: [T[0], T[1], U];
3: [T[0], T[1], T[2], U];
4: [T[0], T[1], T[2], T[3], U];
5: [T[0], T[1], T[2], T[3], T[4], U];
6: [T[0], T[1], T[2], T[3], T[4], T[5], U];
7: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], U];
8: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], U];
}[Measure<T["length"]>];
declare type ArgumentNames<T extends any[]> = FixedSizeArray<T["length"], string>;
declare type AsArray<T> = T extends any[] ? T : [T];
export declare type Asset = {
outdir?: string;
/**
* rebase relative url, default is true when format is 'cjs' or 'esm'.
*/
rebase?: boolean;
name?: string | ((filePath: string) => string);
/**
* Specify the limit size to inline
* @default 0
*/
limit?: number;
publicPath?: string | ((filePath: string) => string);
};
export declare type AssetChunk = {
type: 'asset';
contents: string | Buffer;
/**
* absolute file path
*/
fileName: string;
originalFileName?: string;
entryPoint?: string;
};
export declare type AssetNormalized = Required<Asset>;
declare class AsyncHook<T, R, AdditionalOptions = UnsetAdditionalOptions> extends Hook<T, R, AdditionalOptions> {
tapAsync(
options: string | Tap & IfSet<AdditionalOptions>,
fn: (...args: Append<AsArray<T>, InnerCallback<Error, R>>) => void
): void;
tapPromise(
options: string | Tap & IfSet<AdditionalOptions>,
fn: (...args: AsArray<T>) => Promise<R>
): void;
}
declare class AsyncSeriesBailHook<T, R, AdditionalOptions = UnsetAdditionalOptions> extends AsyncHook<T, R, AdditionalOptions> {}
declare class AsyncSeriesHook<T, AdditionalOptions = UnsetAdditionalOptions> extends AsyncHook<T, void, AdditionalOptions> {}
declare class AsyncSeriesWaterfallHook<T, AdditionalOptions = UnsetAdditionalOptions> extends AsyncHook<T, AsArray<T>[0], AdditionalOptions> {}
export declare interface BuildConfig extends Required<Omit<CLIConfig, 'sideEffects' | 'chunkNames'>> {
chunkNames?: string;
sideEffects?: SideEffects;
logger: ILogger;
resolve: ResolveNormalized;
asset: AssetNormalized;
css_resolve: (id: string, dir: string) => string;
node_resolve: (id: string, dir: string, kind?: ImportKind) => string;
}
export declare interface BuilderResolveOptions {
kind?: ImportKind;
importer?: string;
resolveDir?: string;
skipSideEffects?: boolean;
}
export declare interface BuilderResolveResult {
path: string;
suffix?: string;
external?: boolean;
sideEffects?: boolean;
}
export declare interface CacheValue extends Source {
originCode: string;
}
export declare type Callback = (err?: any) => void;
declare type Callback_2<E, T> = (error: E | null, result?: T) => void;
export declare type Chunk = AssetChunk | JsChunk;
export declare const enum ChunkType {
chunk = "chunk",
asset = "asset"
}
export declare interface CLIConfig extends UserConfig {
/**
* project root dir
*/
root?: string;
}
export declare interface CodeFrameFileOption {
filePath: string;
}
/**
* Compatible with esbuild
*/
export declare interface CodeFrameLineOption {
filePath: string;
lineText: string;
start?: CodeFramePosition;
length?: number;
}
export declare interface CodeFrameNormalOption {
filePath: string;
fileContent: string;
start?: CodeFramePosition;
end?: CodeFramePosition;
}
export declare type CodeFrameOption = CodeFrameFileOption | CodeFrameNormalOption | CodeFrameLineOption;
export declare interface CodeFramePosition {
line: number;
column?: number;
}
export declare interface ControllerOption {
/**
* No stack displayed
* @default `true`
*/
noStack?: boolean;
/**
* No color displayed
* @default `false`
*/
noColor?: boolean;
}
declare type Define = Record<string, string>;
export declare enum ErrorLevel {
Ignore = 0,
Warn = 1,
Error = 2
}
export { EsbuildError }
export declare interface EsbuildResultInfo {
errors: EsbuildError[];
warnings: EsbuildError[];
}
declare type External_2 = (string | RegExp)[];
export declare type ExtraContext = Record<string, any>;
declare type FixedSizeArray<T extends number, U> = T extends 0
? void[]
: ReadonlyArray<U> & {
0: U;
length: T;
};
export declare type Format = 'esm' | 'cjs' | 'umd' | 'iife';
export declare function formatError(err: Error | LibuildErrorInstance): string;
declare type FullTap = Tap & {
type: "sync" | "async" | "promise",
fn: Function
}
declare type GenerateScopedNameFunction = (name: string, filename: string, css: string) => string;
declare type Globals = Record<any, any>;
declare class Hook<T, R, AdditionalOptions = UnsetAdditionalOptions> {
constructor(args?: ArgumentNames<AsArray<T>>, name?: string);
name: string | undefined;
taps: FullTap[];
intercept(interceptor: HookInterceptor<T, R, AdditionalOptions>): void;
isUsed(): boolean;
callAsync(...args: Append<AsArray<T>, Callback_2<Error, R>>): void;
promise(...args: AsArray<T>): Promise<R>;
tap(options: string | Tap & IfSet<AdditionalOptions>, fn: (...args: AsArray<T>) => R): void;
withOptions(options: TapOptions & IfSet<AdditionalOptions>): Omit<this, "call" | "callAsync" | "promise">;
}
declare interface HookInterceptor<T, R, AdditionalOptions = UnsetAdditionalOptions> {
name?: string;
tap?: (tap: FullTap & IfSet<AdditionalOptions>) => void;
call?: (...args: any[]) => void;
loop?: (...args: any[]) => void;
error?: (err: Error) => void;
result?: (result: R) => void;
done?: () => void;
register?: (tap: FullTap & IfSet<AdditionalOptions>) => FullTap & IfSet<AdditionalOptions>;
}
export declare interface IBuilderBase {
build: () => Promise<void>;
reBuild: (type: 'link' | 'change') => Promise<void>;
close: (callack?: Callback) => void;
}
declare type IfSet<X> = X extends UnsetAdditionalOptions ? {} : X;
export declare interface ILibuilder {
name?: string;
version: string;
compilation: IBuilderBase;
hooks: ILibuilderHooks;
STAGE: ILibuilderStage;
userConfig: CLIConfig;
config: BuildConfig;
plugins: LibuildPlugin[];
outputChunk: Map<string, Chunk>;
virtualModule: Map<string, string>;
init: (config: CLIConfig) => Promise<void>;
build: () => Promise<void>;
close: (callBack?: Callback) => Promise<void>;
emitAsset: ((name: string, chunk: AssetChunk) => void) & ((name: string, chunk: JsChunk) => void) & ((name: string, chunk: string) => void);
watchedFiles: Set<string>;
addWatchFile: (id: string) => void;
resolve: (source: string, options?: BuilderResolveOptions) => Promise<BuilderResolveResult>;
loadSvgr: (path: string) => Promise<LoadSvgrResult | void>;
getTransformContext: (path: string) => ITransformContext;
getSourcemapContext: (path: string) => ISourcemapContext;
report: (error: any) => void;
throw: (message: string, option: LibuildErrorParams) => void;
printErrors: () => void;
getErrors: () => LibuildFailure;
clearErrors: () => void;
removeError: (...errors: LibuildErrorInstance[]) => void;
}
export declare interface ILibuilderHooks {
/**
* Asynchronous initialization. Executed after normalized `buildConfig` and `plugins`.
*/
initialize: AsyncSeriesHook<[], void>;
/**
* Equal to esbuild#onResolve and rollup#resolveId
*/
resolve: AsyncSeriesBailHook<[ResolveArgs], ResolveResult | undefined>;
/**
* Equal to esbuild#onLoad and rollup#load
*/
load: AsyncSeriesBailHook<[LoadArgs], LoadResult | undefined | void>;
/**
*
*/
transform: AsyncSeriesWaterfallHook<Source>;
/**
* Modify the chunk
*/
processAsset: AsyncSeriesWaterfallHook<[Chunk]>;
/**
* After esbuild onStart, also called by watchChange
*/
startCompilation: AsyncSeriesHook<[]>;
/**
* After esbuild onEnd, also called by watchChange
*/
endCompilation: AsyncSeriesHook<[LibuildFailure]>;
/**
* Post processing for assets
*/
processAssets: AsyncSeriesHook<[Map<string, Chunk>, LibuildManifest]>;
/**
* Watch related hook
*/
watchChange: SyncHook<[string[]]>;
/**
* Before close
*/
shutdown: AsyncSeriesHook<[]>;
}
export declare interface ILibuilderStage {
/**
* Execute Before Internal Plugin
*/
PRE_INTERNAL: number;
/**
* Execute After Internal Plugin
*/
POST_INTERNAL: number;
}
export declare abstract class ILogger {
abstract timesLog: Map<Label, number>;
abstract info(...msg: string[]): void;
abstract warn(...msg: string[]): void;
abstract error(...msg: string[]): void;
abstract debug(...msg: string[]): void;
abstract time(label: Label): void;
abstract timeEnd(label: Label): void;
}
export declare interface ILoggerOptions {
/**
* @default 'info'
*/
level?: LogLevel;
/**
* @default false
*/
timestamp?: boolean;
}
declare type InnerCallback<E, T> = (error?: E | null | false, result?: T) => void;
declare type Input = {
[name: string]: string;
} | string[];
export declare function insertSpace(rawLines: string, line: number, width: number): string;
/**
* we can't use instanceof LibuildError, because it may not be an singleton class
* @param err
* @returns
*/
export declare function isLibuildErrorInstance(err: unknown): err is LibuildError;
export declare interface ISourcemapContext {
addSourceMap: (pluginId: number, map?: SourceMap) => void;
getInlineSourceMap: () => string;
getSourceMap: () => SourceMap | undefined;
getSourceMapChain: () => SourceMap[];
genPluginId: (id: string) => number;
}
export declare interface ITransformContext extends ISourcemapContext {
addTransformResult: (pluginId: number, result: CacheValue) => void;
getValidCache: (pluginId: number, code: string) => undefined | CacheValue;
}
export declare type JsChunk = {
type: 'chunk';
contents: string;
/**
* absolute file path
*/
fileName: string;
originalFileName?: string;
map?: SourceMap;
entryPoint?: string;
modules?: Record<string, any>;
isEntry: boolean;
};
declare type Label = string;
export declare class Libuilder implements ILibuilder {
static run(config?: CLIConfig, name?: string): Promise<Libuilder | Libuilder[]>;
static create(config?: CLIConfig, name?: string): Promise<Libuilder>;
compilation: IBuilderBase;
version: string;
watchedFiles: Set<string>;
hooks: ILibuilderHooks;
STAGE: ILibuilderStage;
userConfig: CLIConfig;
config: BuildConfig;
plugins: LibuildPlugin[];
outputChunk: Map<string, Chunk>;
virtualModule: Map<string, string>;
name?: string;
private errors;
private watcher?;
private transformContextMap;
private sourcemapContextMap;
init(config: CLIConfig): Promise<void>;
build(): Promise<void>;
close(callback?: Callback): Promise<void>;
emitAsset(name: string, chunk: string | Chunk): void;
addWatchFile(id: string): void;
resolve(_source: string, _opt?: BuilderResolveOptions): Promise<BuilderResolveResult>;
loadSvgr(_path: string): Promise<void>;
getTransformContext(path: string): TransformContext;
getSourcemapContext(path: string): SourcemapContext;
report(err: any): void;
throw(message: string, opts?: LibuildErrorParams): void;
printErrors(): void;
getErrors(): LibuildFailure;
clearErrors(): void;
removeError(...errors: LibuildErrorInstance[]): void;
}
export declare class LibuildError extends Error implements LibuildErrorInstance {
static from(err: unknown, opt?: LibuildErrorParams): LibuildError;
readonly prefixCode: string;
readonly code: string;
readonly reason?: string;
readonly hint?: string;
readonly referenceUrl?: string;
private codeFrame?;
private _controller;
private readonly _level;
constructor(code: string, message: string, opts?: LibuildErrorParams);
get level(): "Ignore" | "Warn" | "Error";
get path(): string | undefined;
set path(file: string | undefined);
private printCodeFrame;
toString(): string;
setControllerOption(opt: ControllerOption): void;
setCodeFrame(opt: CodeFrameOption): void;
isSame(error: LibuildError): boolean;
}
export declare interface LibuildErrorInstance {
prefixCode?: string;
code: string;
message: string;
reason?: string;
stack?: string;
path?: string;
/**
* @default`'Error'`
*/
level?: keyof typeof ErrorLevel;
hint?: string;
referenceUrl?: string;
setControllerOption: (opt: ControllerOption) => void;
setCodeFrame: (opt: CodeFrameOption) => void;
}
export declare type LibuildErrorParams = Omit<LibuildErrorInstance, 'code' | 'message' | 'path' | 'setControllerOption' | 'setCodeFrame' | 'toOverlayPayload'> & {
code?: string;
controller?: ControllerOption;
codeFrame?: CodeFrameOption;
};
export declare class LibuildFailure extends Error {
readonly errors: LibuildErrorInstance[];
readonly warnings: LibuildErrorInstance[];
readonly logLevel: string;
constructor(errors: LibuildErrorInstance[], warnings: LibuildErrorInstance[], logLevel: string);
toString(): string;
}
export declare type LibuildManifest = {
metafile: Metafile;
config: BuildOptions;
};
export declare interface LibuildPlugin<T extends ExtraContext = ExtraContext> {
name: string;
apply: (compiler: SafeMerge<ILibuilder, T>) => void;
}
export declare type LoadArgs = Pick<OnLoadArgs, 'path'> & Pick<OnResolveResult, 'pluginData'>;
declare class Loader {
finalSource?: string | undefined;
constructor(root: string, plugins: Plugin_2[]);
fetch(file: string, relativeTo: string, depTrace: string): Promise<{
[key: string]: string;
}>;
}
export declare type LoadResult = Pick<OnLoadResult, 'contents' | 'loader' | 'resolveDir'> & {
map?: SourceMap;
};
declare type LoadSvgrResult = {
contents: string;
loader: Loader_2;
};
declare type LocalsConventionFunction = (originalClassName: string, generatedClassName: string, inputFile: string) => string;
/**
* Options for log level.
*/
export declare type LogLevel = 'silent' | 'error' | 'warning' | 'info' | 'debug' | 'verbose';
declare type Measure<T extends number> = T extends 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
? T
: never;
declare type Minify = 'esbuild' | 'terser' | false | MinifyOptions;
declare type Platform = 'node' | 'browser';
export declare type PostcssOptions = {
processOptions?: ProcessOptions;
plugins?: AcceptedPlugin[];
};
/**
* @experimental
*/
export declare type Redirect = {
alias?: boolean;
style?: boolean;
asset?: boolean;
};
/**
* Options for the resolver.
*/
export declare type Resolve = {
/**
* This is only valid for enhanced-resolve
*/
alias?: Record<string, string>;
mainFields?: string[];
/**
* @internal This is only valid for enhanced-resolve
*/
mainFiles?: string[];
/**
* @internal This is only valid for enhanced-resolve
*/
preferRelative?: boolean;
};
export declare type ResolveArgs = Pick<OnResolveArgs, 'importer' | 'path' | 'resolveDir' | 'kind'>;
export declare type ResolveNormalized = Required<Resolve>;
export declare type ResolveResult = Pick<OnResolveResult, 'path' | 'external' | 'namespace' | 'sideEffects' | 'suffix'>;
/**
* Only merge additional fields from U to T.
*/
export declare type SafeMerge<T, U> = T & {
[K in keyof U as Exclude<K, keyof T>]: U[K];
};
export { sassOptions }
export declare type SideEffects = RegExp[] | boolean | ((id: string, external: boolean) => boolean);
export declare type Source = {
code: string;
map?: SourceMap;
path: string;
loader?: string;
/**
* Whether enable cache.
* @default true
*/
cache?: boolean;
};
export declare interface SourceMap {
mappings: string;
names: string[];
sources: (string | null)[];
version: number;
sourcesContent?: (string | null)[];
}
declare type SourceMap_2 = boolean | 'inline' | 'external';
declare class SourcemapContext implements ISourcemapContext {
private enableSourceMap?;
private sourceMapChain;
private sourceMapDirty;
private cachedInlineSourceMap;
private cachedSourceMap;
private pluginIdMap;
constructor(enableSourceMap?: boolean | undefined);
private markSourceMapStatus;
addSourceMap(pluginId: number, map?: SourceMap): void;
getInlineSourceMap(): string;
getSourceMap(): SourceMap | undefined;
getSourceMapChain(): SourceMap[];
genPluginId(name: string): number;
}
export declare interface Style {
inject?: boolean;
sass?: {
additionalData?: AdditionalData;
implementation?: object | string;
sassOptions?: sassOptions;
};
less?: {
additionalData?: AdditionalData;
implementation?: object | string;
lessOptions?: Less.Options;
};
postcss?: PostcssOptions;
autoModules?: boolean | RegExp;
modules?: {
localsConvention?: 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly' | LocalsConventionFunction;
scopeBehaviour?: 'global' | 'local';
globalModulePaths?: RegExp[];
generateScopedName?: string | GenerateScopedNameFunction;
hashPrefix?: string;
exportGlobals?: boolean;
root?: string;
resolve?: (file: string) => string | Promise<string>;
Loader?: typeof Loader;
getJSON?: (cssFilename: string, json: {
[name: string]: string;
}, outputFilename?: string) => void;
};
}
declare class SyncHook<T, R = void, AdditionalOptions = UnsetAdditionalOptions> extends Hook<T, R, AdditionalOptions> {
call(...args: AsArray<T>): R;
}
declare type Tap = TapOptions & {
name: string;
};
declare type TapOptions = {
before?: string;
stage?: number;
};
export declare function toLevel(level: keyof typeof ErrorLevel): ErrorLevel;
export declare function transform(err: any, opt?: LibuildErrorParams): LibuildError;
declare class TransformContext extends SourcemapContext implements ITransformContext {
private enableCache?;
private cachedTransformResult;
constructor(enableCache?: boolean | undefined, enableSourceMap?: boolean);
addTransformResult(pluginId: number, result: CacheValue): void;
getValidCache(pluginId: number, code: string): CacheValue | undefined;
}
declare class UnsetAdditionalOptions {
_UnsetAdditionalOptions: true
}
export declare interface UserConfig {
/**
* @default true
*/
autoExternal?: boolean | {
dependencies?: boolean;
peerDependencies?: boolean;
};
/**
* @default true
*/
bundle?: boolean;
/**
* Input to the bundling algorithm.
*
* Only valid when bundle is 'true'
* @default { index: './src/index.ts '}
*/
input?: Input;
/**
* The directory for source.
*
* Only valid when bundle is 'false', it will transform all files in sourceDir
* @default 'src'
*/
sourceDir?: string;
/**
* The directory for output
* @default 'dist'
*/
outdir?: string;
/**
* @see https://esbuild.github.io/api/#outbase
* @default 'src'
*/
outbase?: string;
/**
* Options for esbuild, it may disable some of the functions of libuild
* @experimental
*/
esbuildOptions?: (options: BuildOptions) => BuildOptions;
/**
* @see https://esbuild.github.io/api/#entry-names
*/
entryNames?: string;
/**
* @see https://esbuild.github.io/api/#chunk-names
*/
chunkNames?: string;
/**
* Module format
* @default 'esm'
*/
format?: Format;
/**
* Code splitting
* @default false
*/
splitting?: boolean;
/**
* Minify JS
* @default false
*/
minify?: Minify;
/**
* When file changed builder will rebuild under watch mode.
* @default false
*/
watch?: boolean;
/**
* The level of the console log
* @default 'info'
*/
logLevel?: LogLevel;
/**
* Options for enhanced-resolve
*/
resolve?: Resolve;
/**
* Plugins for libuild
*/
plugins?: LibuildPlugin[];
/**
* Compile target
* @see https://esbuild.github.io/api/#target
* @default 'es2015'
*/
target?: string;
/**
* The mode of sourcemap
* @default false
*/
sourceMap?: SourceMap_2;
/**
* Global variables, only used in umd format
* @default {}
*/
globals?: Globals;
/**
* Exclude it from your build
* Default Excluded your dependencies and peerDependencies
*/
external?: External_2;
/**
* @see https://esbuild.github.io/api/#define
*/
define?: Define;
/**
* @see https://esbuild.github.io/api/#platform
* @default 'node'
*/
platform?: Platform;
/**
* Emit esbuild metafile
* @see https://esbuild.github.io/api/#metafile
* @default false
*/
metafile?: boolean;
/**
* Options for style
*/
style?: Style;
/**
* Options for asset
*/
asset?: Asset;
/**
* @see https://esbuild.github.io/api/#loader
*/
loader?: Record<string, Loader_2>;
/**
* @see https://esbuild.github.io/api/#inject
*/
inject?: string[];
/**
* @see https://esbuild.github.io/api/#jsx
* @default 'automatic'
*/
jsx?: 'automatic' | 'preserve' | 'transform';
/**
* Module sideEffects, it will invalidate the sideEffects field in package.json
*/
sideEffects?: SideEffects;
/**
* Redirect id when bundle is false
*/
redirect?: Redirect;
/**
* Cache for transform hooks, accelerate incremental build
* @default true
*/
transformCache?: boolean;
}
export declare function warpErrors(libuildErrors: LibuildError[], logLevel?: LogLevel): LibuildFailure;
export { }