mirror of
https://github.com/strapi/strapi.git
synced 2025-08-31 04:03:50 +00:00
feat(pack-up): enable config via nodeAPI & allow bundles to have own tsconfig (#18440)
* feat: add ability to pass config & have tsconfig per bundle * feat: use node:module builtinModules for node stuff * chore: remove builtins from externals
This commit is contained in:
parent
8632eeaf18
commit
25d1ceaa44
@ -10,6 +10,5 @@ export default defineConfig({
|
||||
},
|
||||
],
|
||||
dist: './dist',
|
||||
externals: ['node:fs', 'node:path'],
|
||||
runtime: 'node',
|
||||
});
|
||||
|
@ -10,6 +10,5 @@ export default defineConfig({
|
||||
},
|
||||
],
|
||||
dist: './dist',
|
||||
externals: ['child_process', 'node:fs', 'node:path', 'os', 'path'],
|
||||
runtime: 'node',
|
||||
});
|
||||
|
@ -3,5 +3,4 @@ import { defineConfig } from '@strapi/pack-up';
|
||||
|
||||
export default defineConfig({
|
||||
runtime: 'node',
|
||||
externals: ['crypto', 'http', 'https', 'os', 'path', 'stream', 'zlib'],
|
||||
});
|
||||
|
@ -3,13 +3,6 @@ import { defineConfig } from '@strapi/pack-up';
|
||||
|
||||
export default defineConfig({
|
||||
externals: [
|
||||
'crypto',
|
||||
'node:async_hooks',
|
||||
'node:path',
|
||||
'path',
|
||||
'stream',
|
||||
'timers',
|
||||
'tty',
|
||||
/**
|
||||
* Knex dependencies, if we don't mark these as external
|
||||
* they will be included in the bundle which means they
|
||||
|
@ -2,6 +2,5 @@
|
||||
import { defineConfig } from '@strapi/pack-up';
|
||||
|
||||
export default defineConfig({
|
||||
externals: ['node:stream'],
|
||||
runtime: 'node',
|
||||
});
|
||||
|
@ -2,7 +2,6 @@
|
||||
import { defineConfig } from '@strapi/pack-up';
|
||||
|
||||
export default defineConfig({
|
||||
externals: ['crypto', 'fs', 'node:fs', 'node:os', 'node:path', 'node:readline', 'os', 'path'],
|
||||
preserveModules: true,
|
||||
runtime: 'node',
|
||||
});
|
||||
|
@ -9,6 +9,5 @@ export default defineConfig({
|
||||
import: './dist/plopfile.mjs',
|
||||
},
|
||||
],
|
||||
externals: ['node:path', 'path'],
|
||||
runtime: 'node',
|
||||
});
|
||||
|
@ -2,6 +2,5 @@
|
||||
import { defineConfig } from '@strapi/pack-up';
|
||||
|
||||
export default defineConfig({
|
||||
externals: ['stream', 'fs', 'path'],
|
||||
runtime: 'node',
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ export default defineConfig({
|
||||
require: './dist/cli.js',
|
||||
},
|
||||
],
|
||||
externals: ['fs', 'path', 'child_process', 'fs/promises', 'module', 'os'],
|
||||
externals: ['node:module'],
|
||||
runtime: 'node',
|
||||
minify: false,
|
||||
sourcemap: true,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { build as nodeBuild, BuildOptions } from '../../node/build';
|
||||
import { build as nodeBuild, BuildCLIOptions } from '../../node/build';
|
||||
import { handleError } from '../errors';
|
||||
|
||||
export const build = async (options: Omit<BuildOptions, 'cwd'>) => {
|
||||
export const build = async (options: BuildCLIOptions) => {
|
||||
try {
|
||||
await nodeBuild(options);
|
||||
} catch (err) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { WatchOptions, watch as nodeWatch } from '../../node/watch';
|
||||
import { WatchCLIOptions, watch as nodeWatch } from '../../node/watch';
|
||||
import { handleError } from '../errors';
|
||||
|
||||
export const watch = async (options: WatchOptions) => {
|
||||
export const watch = async (options: WatchCLIOptions) => {
|
||||
try {
|
||||
await nodeWatch(options);
|
||||
} catch (err) {
|
||||
|
@ -4,7 +4,13 @@ export * from './node/check';
|
||||
export * from './node/init';
|
||||
|
||||
export { defineConfig } from './node/core/config';
|
||||
export type { Config } from './node/core/config';
|
||||
export type {
|
||||
Config,
|
||||
ConfigBundle,
|
||||
ConfigOptions,
|
||||
ConfigProperty,
|
||||
ConfigPropertyResolver,
|
||||
} from './node/core/config';
|
||||
|
||||
export { defineTemplate, definePackageFeature, definePackageOption } from './node/templates/create';
|
||||
export type {
|
||||
|
@ -4,7 +4,7 @@ import os from 'os';
|
||||
|
||||
import { CommonCLIOptions } from '../types';
|
||||
|
||||
import { loadConfig } from './core/config';
|
||||
import { loadConfig, type Config } from './core/config';
|
||||
import { isError } from './core/errors';
|
||||
import { getExportExtensionMap, validateExportsOrdering } from './core/exports';
|
||||
import { createLogger } from './core/logger';
|
||||
@ -13,14 +13,34 @@ import { createBuildContext } from './createBuildContext';
|
||||
import { BuildTask, createBuildTasks } from './createTasks';
|
||||
import { TaskHandler, taskHandlers } from './tasks';
|
||||
|
||||
export interface BuildOptions extends CommonCLIOptions {
|
||||
cwd?: string;
|
||||
interface BuildCLIOptions extends CommonCLIOptions {
|
||||
minify?: boolean;
|
||||
sourcemap?: boolean;
|
||||
}
|
||||
|
||||
export const build = async (opts: BuildOptions = {}) => {
|
||||
const { silent, debug, cwd = process.cwd(), ...configOptions } = opts;
|
||||
interface BuildWithConfigFile extends BuildCLIOptions {
|
||||
configFile?: true;
|
||||
config?: never;
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
interface BuildWithoutConfigFile extends BuildCLIOptions {
|
||||
configFile: false;
|
||||
config?: Config;
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
type BuildOptions = BuildWithConfigFile | BuildWithoutConfigFile;
|
||||
|
||||
const build = async (opts: BuildOptions = {}) => {
|
||||
const {
|
||||
silent,
|
||||
debug,
|
||||
cwd = process.cwd(),
|
||||
configFile = true,
|
||||
config: providedConfig,
|
||||
...configOptions
|
||||
} = opts;
|
||||
|
||||
const logger = createLogger({ silent, debug });
|
||||
|
||||
@ -66,13 +86,18 @@ export const build = async (opts: BuildOptions = {}) => {
|
||||
|
||||
packageJsonLoader.succeed('Verified package.json');
|
||||
|
||||
/**
|
||||
* If configFile is true – which is the default, atempt to load the config
|
||||
* otherwise if it's explicitly false then we suspect there might be a config passed
|
||||
* in the options, so we'll use that instead.
|
||||
*/
|
||||
const config = configFile ? await loadConfig({ cwd, logger }) : providedConfig;
|
||||
|
||||
/**
|
||||
* We create tasks based on the exports of the package.json
|
||||
* their handlers are then ran in the order of the exports map
|
||||
* and results are logged to see gradual progress.
|
||||
*/
|
||||
const config = await loadConfig({ cwd, logger });
|
||||
|
||||
const buildContextLoader = ora(`Creating build context ${os.EOL}`).start();
|
||||
|
||||
const extMap = getExportExtensionMap();
|
||||
@ -126,3 +151,6 @@ export const build = async (opts: BuildOptions = {}) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export { build };
|
||||
export type { BuildOptions, BuildCLIOptions, BuildWithConfigFile, BuildWithoutConfigFile };
|
||||
|
@ -70,6 +70,7 @@ interface ConfigBundle {
|
||||
import?: string;
|
||||
require?: string;
|
||||
runtime?: Runtime;
|
||||
tsconfig?: string;
|
||||
types?: string;
|
||||
}
|
||||
|
||||
@ -99,6 +100,12 @@ interface ConfigOptions {
|
||||
preserveModules?: boolean;
|
||||
sourcemap?: boolean;
|
||||
runtime?: Runtime;
|
||||
/**
|
||||
* @description path to the tsconfig file to use for the bundle.
|
||||
*
|
||||
* @default tsconfig.build.json
|
||||
*/
|
||||
tsconfig?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,4 +135,4 @@ export function resolveConfigProperty<T>(prop: ConfigProperty<T> | undefined, in
|
||||
}
|
||||
|
||||
export { loadConfig, defineConfig, CONFIG_FILE_NAMES };
|
||||
export type { Config };
|
||||
export type { Config, ConfigOptions, ConfigBundle, ConfigPropertyResolver, ConfigProperty };
|
||||
|
@ -65,7 +65,7 @@ const createBuildContext = async ({
|
||||
}: BuildContextArgs): Promise<BuildContext> => {
|
||||
const tsConfig = loadTsConfig({
|
||||
cwd,
|
||||
path: 'tsconfig.build.json',
|
||||
path: resolveConfigProperty(config.tsconfig, 'tsconfig.build.json'),
|
||||
logger,
|
||||
});
|
||||
|
||||
|
@ -143,6 +143,7 @@ const createTasks =
|
||||
exportPath: bundle.source,
|
||||
sourcePath: bundle.source,
|
||||
targetPath: bundle.types,
|
||||
tsconfig: bundle.tsconfig,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { Observable } from 'rxjs';
|
||||
import ts from 'typescript';
|
||||
|
||||
import { isError } from '../../core/errors';
|
||||
import { loadTsConfig } from '../../core/tsconfig';
|
||||
|
||||
import { printDiagnostic } from './diagnostic';
|
||||
import { DtsBaseTask } from './types';
|
||||
@ -33,7 +34,18 @@ const dtsBuildTask: TaskHandler<DtsBuildTask> = {
|
||||
return new Observable((subscriber) => {
|
||||
Promise.all(
|
||||
task.entries.map(async (entry) => {
|
||||
if (!ctx.ts) {
|
||||
/**
|
||||
* Entry level tsconfig's take precedence
|
||||
*/
|
||||
const tsconfig = entry.tsconfig
|
||||
? loadTsConfig({
|
||||
cwd: ctx.cwd,
|
||||
path: entry.tsconfig,
|
||||
logger: ctx.logger,
|
||||
})
|
||||
: ctx.ts;
|
||||
|
||||
if (!tsconfig) {
|
||||
ctx.logger.warn(
|
||||
`You've added a types entry but no tsconfig.json was found for ${entry.targetPath}. Skipping...`
|
||||
);
|
||||
@ -41,7 +53,7 @@ const dtsBuildTask: TaskHandler<DtsBuildTask> = {
|
||||
return;
|
||||
}
|
||||
|
||||
const program = ts.createProgram(ctx.ts.config.fileNames, ctx.ts.config.options);
|
||||
const program = ts.createProgram(tsconfig.config.fileNames, tsconfig.config.options);
|
||||
|
||||
const emitResult = program.emit();
|
||||
|
||||
|
@ -3,6 +3,12 @@ interface DtsTaskEntry {
|
||||
exportPath: string;
|
||||
sourcePath: string;
|
||||
targetPath: string;
|
||||
/**
|
||||
* Allow a particular task to have it's own tsconfig
|
||||
* great for when you're creating a server & web bundle
|
||||
* package.
|
||||
*/
|
||||
tsconfig?: string;
|
||||
}
|
||||
|
||||
interface DtsBaseTask {
|
||||
|
@ -4,6 +4,7 @@ import { Observable } from 'rxjs';
|
||||
import ts from 'typescript';
|
||||
|
||||
import { isError } from '../../core/errors';
|
||||
import { loadTsConfig } from '../../core/tsconfig';
|
||||
|
||||
import { printDiagnostic } from './diagnostic';
|
||||
import { DtsBaseTask } from './types';
|
||||
@ -36,7 +37,18 @@ const dtsWatchTask: TaskHandler<DtsWatchTask, ts.Diagnostic> = {
|
||||
return new Observable((subscriber) => {
|
||||
Promise.all(
|
||||
task.entries.map(async (entry) => {
|
||||
if (!ctx.ts) {
|
||||
/**
|
||||
* Entry level tsconfig's take precedence
|
||||
*/
|
||||
const tsconfig = entry.tsconfig
|
||||
? loadTsConfig({
|
||||
cwd: ctx.cwd,
|
||||
path: entry.tsconfig,
|
||||
logger: ctx.logger,
|
||||
})
|
||||
: ctx.ts;
|
||||
|
||||
if (!tsconfig) {
|
||||
ctx.logger.warn(
|
||||
`You've added a types entry but no tsconfig.json was found for ${entry.targetPath}. Skipping...`
|
||||
);
|
||||
@ -46,7 +58,7 @@ const dtsWatchTask: TaskHandler<DtsWatchTask, ts.Diagnostic> = {
|
||||
|
||||
const compilerHost = ts.createWatchCompilerHost(
|
||||
'tsconfig.build.json',
|
||||
ctx.ts.config.options,
|
||||
tsconfig.config.options,
|
||||
ts.sys,
|
||||
ts.createEmitAndSemanticDiagnosticsBuilderProgram,
|
||||
(diagnostic) => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { builtinModules } from 'node:module';
|
||||
import path from 'path';
|
||||
import { InlineConfig, createLogger } from 'vite';
|
||||
|
||||
@ -82,7 +83,15 @@ const resolveViteConfig = (ctx: BuildContext, task: ViteBaseTask) => {
|
||||
|
||||
const name = idParts[0].startsWith('@') ? `${idParts[0]}/${idParts[1]}` : idParts[0];
|
||||
|
||||
if (name && external.includes(name)) {
|
||||
const builtinModulesWithNodePrefix = [
|
||||
...builtinModules,
|
||||
...builtinModules.map((modName) => `node:${modName}`),
|
||||
];
|
||||
|
||||
if (
|
||||
(name && external.includes(name)) ||
|
||||
(name && builtinModulesWithNodePrefix.includes(name))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { Observable, distinctUntilChanged, scan, startWith, switchMap } from 'rx
|
||||
|
||||
import { CommonCLIOptions } from '../types';
|
||||
|
||||
import { CONFIG_FILE_NAMES, loadConfig } from './core/config';
|
||||
import { CONFIG_FILE_NAMES, Config, loadConfig } from './core/config';
|
||||
import { getExportExtensionMap, validateExportsOrdering } from './core/exports';
|
||||
import { createLogger } from './core/logger';
|
||||
import { loadPkg, validatePkg } from './core/pkg';
|
||||
@ -12,12 +12,24 @@ import { createBuildContext } from './createBuildContext';
|
||||
import { WatchTask, createWatchTasks } from './createTasks';
|
||||
import { TaskHandler, taskHandlers } from './tasks';
|
||||
|
||||
export interface WatchOptions extends CommonCLIOptions {
|
||||
interface WatchCLIOptions extends CommonCLIOptions {}
|
||||
|
||||
interface WatchOptionsWithoutConfig extends WatchCLIOptions {
|
||||
configFile?: true;
|
||||
config?: never;
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
export const watch = async (opts: WatchOptions) => {
|
||||
const { silent, debug, cwd = process.cwd() } = opts;
|
||||
interface WatchOptionsWithConfig extends WatchCLIOptions {
|
||||
configFile: false;
|
||||
config?: Config;
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
type WatchOptions = WatchOptionsWithConfig | WatchOptionsWithoutConfig;
|
||||
|
||||
const watch = async (opts: WatchOptions) => {
|
||||
const { silent, debug, cwd = process.cwd(), configFile = true, config: providedConfig } = opts;
|
||||
|
||||
const logger = createLogger({ silent, debug });
|
||||
|
||||
@ -111,12 +123,17 @@ export const watch = async (opts: WatchOptions) => {
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* If configFile is true – which is the default, atempt to load the config
|
||||
* otherwise if it's explicitly false then we suspect there might be a config passed
|
||||
* in the options, so we'll use that instead.
|
||||
*/
|
||||
const config = configFile ? await loadConfig({ cwd, logger }) : providedConfig;
|
||||
/**
|
||||
* We create tasks based on the exports of the package.json
|
||||
* their handlers are then ran in the order of the exports map
|
||||
* and results are logged to see gradual progress.
|
||||
*/
|
||||
const config = await loadConfig({ cwd, logger });
|
||||
|
||||
const extMap = getExportExtensionMap();
|
||||
|
||||
@ -154,3 +171,6 @@ export const watch = async (opts: WatchOptions) => {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export { watch };
|
||||
export type { WatchOptions, WatchOptionsWithConfig, WatchOptionsWithoutConfig, WatchCLIOptions };
|
||||
|
Loading…
x
Reference in New Issue
Block a user