chore: move commands from admin back to strapi/strapi

This commit is contained in:
Alexandre Bodin 2023-12-19 18:12:02 +01:00
parent da439790ee
commit 3124f474fe
37 changed files with 288 additions and 610 deletions

View File

@ -1,37 +0,0 @@
import { build as nodeBuild, BuildOptions } from '../../node/build';
import { handleUnexpectedError } from '../../node/core/errors';
interface BuildCLIOptions extends BuildOptions {
/**
* @deprecated use `minify` instead
*/
optimization?: boolean;
}
const build = async (options: BuildCLIOptions) => {
try {
if (typeof process.env.STRAPI_ENFORCE_SOURCEMAPS !== 'undefined') {
options.logger.warn(
"[@strapi/strapi]: STRAPI_ENFORCE_SOURCEMAPS is now deprecated. You can enable sourcemaps by passing '--sourcemaps' to the build command."
);
}
if (typeof options.optimization !== 'undefined' && options.optimization !== true) {
options.logger.warn(
"[@strapi/strapi]: The optimization argument is now deprecated. Use '--minify' instead."
);
}
const envSourceMaps = process.env.STRAPI_ENFORCE_SOURCEMAPS === 'true';
await nodeBuild({
...options,
minify: options.optimization ?? options.minify,
sourcemaps: options.sourcemaps || envSourceMaps,
});
} catch (err) {
handleUnexpectedError(err);
}
};
export { build };
export type { BuildCLIOptions };

View File

@ -1,29 +0,0 @@
import { develop as nodeDevelop, DevelopOptions } from '../../node/develop';
import { handleUnexpectedError } from '../../node/core/errors';
interface DevelopCLIOptions extends DevelopOptions {
/**
* @deprecated
*/
browser?: boolean;
}
const develop = async (options: DevelopCLIOptions) => {
try {
if (typeof options.browser !== 'undefined') {
options.logger.warn(
"[@strapi/strapi]: The browser argument, this is now deprecated. Use '--open' instead."
);
}
await nodeDevelop({
...options,
open: options.browser ?? options.open,
});
} catch (err) {
handleUnexpectedError(err);
}
};
export { develop };
export type { DevelopCLIOptions };

View File

@ -1,56 +0,0 @@
import type { StrapiCommand } from '@strapi/strapi';
import type { BuildCLIOptions } from './commands/build';
import type { DevelopCLIOptions } from './commands/develop';
/**
* `$ strapi build`
*/
const build: StrapiCommand = ({ command, ctx }) => {
command
.command('build')
.option('-d, --debug', 'Enable debugging mode with verbose logs', false)
.option('--ignore-prompts', 'Ignore all prompts', false)
.option('--minify', 'Minify the output', true)
.option('--no-optimization', '[deprecated]: use minify instead')
.option('--silent', "Don't log anything", false)
.option('--sourcemap', 'Produce sourcemaps', false)
.option('--stats', 'Print build statistics to the console', false)
.description('Build the strapi admin app')
.action(async (options: BuildCLIOptions) => {
const { build } = await import('./commands/build');
return build({ ...options, ...ctx });
});
};
/**
* `$ strapi develop`
*/
const develop: StrapiCommand = ({ command, ctx }) => {
command
.command('develop')
.alias('dev')
.option('-d, --debug', 'Enable debugging mode with verbose logs', false)
.option('--silent', "Don't log anything", false)
.option('--ignore-prompts', 'Ignore all prompts', false)
.option('--polling', 'Watch for file changes in network directories', false)
.option('--watch-admin', 'Watch the admin panel for hot changes', false)
.option(
'--no-build',
'[deprecated]: there is middleware for the server, it is no longer a separate process'
)
.option(
'--watch-admin',
'[deprecated]: there is now middleware for watching, it is no longer a separate process'
)
.option('--browser <name>', '[deprecated]: use open instead')
.option('--open', 'Open the admin in your browser', true)
.description('Start your Strapi application in development mode')
.action(async (options: DevelopCLIOptions) => {
const { develop } = await import('./commands/develop');
return develop({ ...options, ...ctx });
});
};
export const commands = [build, develop];

View File

@ -1,4 +1 @@
export { commands } from './cli';
export * from './node/build';
export * from './node/develop';
export { DefaultDocument } from '../admin/src/components/DefaultDocument';

View File

@ -1,4 +1,3 @@
export * from './components/DefaultDocument';
export * from './render';
export type { Store } from './core/store/configure';

View File

@ -1,22 +0,0 @@
interface BuildArgs {
optimize?: boolean;
}
declare const build: (args: BuildArgs) => Promise<void>;
interface CleanArgs {
appDir: string;
buildDestDir: string;
}
declare const clean: (args: CleanArgs) => Promise<void>;
interface WatchAdminArgs {
browser?: string | boolean;
open?: boolean;
polling?: boolean;
}
declare const watchAdmin: (args: WatchAdminArgs) => Promise<void>;
export { build, BuildArgs, clean, CleanArgs, watchAdmin, WatchAdminArgs };

View File

@ -1,255 +0,0 @@
'use strict';
const path = require('path');
const fs = require('fs/promises');
const os = require('os');
const chalk = require('chalk');
const ora = require('ora');
const ts = require('typescript');
const { strapiFactory } = require('@strapi/strapi');
const { build: nodeBuild, develop: nodeDevelop } = require('./dist/cli');
/**
* @typedef {Object} BuildArgs
* @property {boolean} optimize
*/
/**
* @deprecated From V5 we will not be exporting build functions from the root export of the admin package.
*
* @type {(args: BuildArgs) => Promise<void>}
*/
async function build({ optimize }) {
console.warn(
"[@strapi/admin]: the build api exported from this package is now deprecated. We don't plan to expose this for public consumption and this will be removed in V5."
);
const enforceSourceMaps = process.env.STRAPI_ENFORCE_SOURCEMAPS === 'true' ?? false;
const cwd = process.cwd();
const logger = createLogger({ debug: true, silent: false, timestamp: false });
const tsconfig = loadTsConfig({
cwd,
path: 'tsconfig.json',
logger,
});
const distDir = tsconfig?.config.options.outDir ?? '';
const strapiInstance = strapiFactory({
// Directories
appDir: cwd,
distDir,
// Options
autoReload: true,
serveAdminPanel: false,
});
await nodeBuild({
cwd,
logger,
minify: optimize,
sourcemaps: enforceSourceMaps,
strapi: strapiInstance,
tsconfig,
});
}
/**
* @typedef {Object} CleanArgs
* @property {string} appDir
* @property {string} buildDestDir
*/
/**
* @deprecated From V5 we will not be exporting clean functions from the root export of the admin package.
*
* @type {(args: CleanArgs) => Promise<void>}
*/
async function clean({ appDir, buildDestDir }) {
console.warn(
"[@strapi/admin]: the clean api exported from this package is now deprecated. We don't plan to expose this for public consumption and this will be removed in V5."
);
const DIRECTORIES = [
path.join(buildDestDir, 'build'),
path.join(appDir, '.cache'),
path.join(appDir, '.strapi'),
];
await Promise.all(DIRECTORIES.map((dir) => fs.rmdir(dir, { recursive: true, force: true })));
}
/**
* @typedef {Object} WatchArgs
* @property {boolean} browser
* @property {boolean} open
* @property {boolean} polling
*/
/**
* @deprecated From V5 we will not be exporting watch functions from the root export of the admin package.
*
* @type {(args: WatchArgs) => Promise<void>}
*/
async function watchAdmin({ browser, open, polling }) {
console.warn(
[
"[@strapi/admin]: the watchAdmin api exported from this package is now deprecated. We don't plan to expose this for public consumption and this will be removed in V5.",
"This command is no longer necessary, the admin's dev server is now injected as a middleware to the strapi server. This is why we're about to start a strapi instance for you.",
].join(os.EOL)
);
const cwd = process.cwd();
const logger = createLogger({ debug: true, silent: false, timestamp: false });
const tsconfig = loadTsConfig({
cwd,
path: 'tsconfig.json',
logger,
});
const distDir = tsconfig?.config.options.outDir ?? '';
const strapiInstance = strapi({
// Directories
appDir: cwd,
distDir,
// Options
autoReload: true,
serveAdminPanel: false,
});
await nodeDevelop({
cwd,
logger,
browser,
open,
polling,
strapi: strapiInstance,
tsconfig,
});
}
/**
* @internal
*/
const createLogger = (options = {}) => {
const { silent = false, debug = false, timestamp = true } = options;
const state = { errors: 0, warning: 0 };
return {
get warnings() {
return state.warning;
},
get errors() {
return state.errors;
},
debug(...args) {
if (silent || !debug) {
return;
}
console.log(
chalk.cyan(`[DEBUG]${timestamp ? `\t[${new Date().toISOString()}]` : ''}`),
...args
);
},
info(...args) {
if (silent) {
return;
}
console.info(
chalk.blue(`[INFO]${timestamp ? `\t[${new Date().toISOString()}]` : ''}`),
...args
);
},
log(...args) {
if (silent) {
return;
}
console.info(chalk.blue(`${timestamp ? `\t[${new Date().toISOString()}]` : ''}`), ...args);
},
warn(...args) {
state.warning += 1;
if (silent) {
return;
}
console.warn(
chalk.yellow(`[WARN]${timestamp ? `\t[${new Date().toISOString()}]` : ''}`),
...args
);
},
error(...args) {
state.errors += 1;
if (silent) {
return;
}
console.error(
chalk.red(`[ERROR]${timestamp ? `\t[${new Date().toISOString()}]` : ''}`),
...args
);
},
spinner(text) {
if (silent) {
return {
succeed() {
return this;
},
fail() {
return this;
},
start() {
return this;
},
text: '',
};
}
return ora(text);
},
};
};
/**
* @internal
*/
const loadTsConfig = ({ cwd, path, logger }) => {
const configPath = ts.findConfigFile(cwd, ts.sys.fileExists, path);
if (!configPath) {
return undefined;
}
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, cwd);
logger.debug(`Loaded user TS config:`, os.EOL, parsedConfig);
return {
config: parsedConfig,
path: configPath,
};
};
module.exports = {
clean,
build,
watchAdmin,
};

View File

@ -20,12 +20,6 @@
}
],
"exports": {
".": {
"types": "./index.d.ts",
"source": "./index.js",
"require": "./index.js",
"default": "./index.js"
},
"./strapi-admin": {
"types": "./dist/admin/src/index.d.ts",
"source": "./admin/src/index.ts",
@ -33,25 +27,24 @@
"require": "./dist/admin/index.js",
"default": "./dist/admin/index.js"
},
"./_internal": {
"types": "./dist/_internal/index.d.ts",
"source": "./_internal/index.ts",
"import": "./dist/_internal.mjs",
"require": "./dist/_internal.js",
"default": "./dist/_internal.js"
},
"./strapi-server": {
"types": "./dist/server/src/index.d.ts",
"source": "./server/src/index.js",
"require": "./strapi-server.js",
"default": "./strapi-server.js"
},
"./cli": {
"source": "./_internal/index.ts",
"import": "./dist/cli.mjs",
"require": "./dist/cli.js",
"default": "./dist/cli.js"
},
"./package.json": "./package.json"
},
"files": [
"dist/",
"strapi-server.js",
"index.js",
"index.d.ts"
"strapi-server.js"
],
"scripts": {
"build": "pack-up build",
@ -69,7 +62,6 @@
},
"dependencies": {
"@casl/ability": "6.5.0",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-toolbar": "1.0.4",
"@reduxjs/toolkit": "1.9.7",
@ -85,28 +77,17 @@
"axios": "1.6.0",
"bcryptjs": "2.4.3",
"boxen": "5.1.2",
"browserslist": "^4.22.1",
"browserslist-to-esbuild": "1.2.0",
"chalk": "^4.1.2",
"chokidar": "3.5.3",
"codemirror5": "npm:codemirror@^5.65.11",
"cross-env": "^7.0.3",
"css-loader": "^6.8.1",
"date-fns": "2.30.0",
"dotenv": "14.2.0",
"esbuild": "0.19.2",
"esbuild-loader": "^2.21.0",
"esbuild-register": "3.5.0",
"execa": "5.1.1",
"fast-deep-equal": "3.1.3",
"find-root": "1.1.0",
"fork-ts-checker-webpack-plugin": "8.0.0",
"formik": "2.4.0",
"fractional-indexing": "3.2.0",
"fs-extra": "10.0.0",
"highlight.js": "^10.4.1",
"history": "^4.9.0",
"html-webpack-plugin": "5.5.0",
"immer": "9.0.19",
"inquirer": "8.2.5",
"invariant": "^2.2.4",
@ -129,14 +110,11 @@
"markdown-it-mark": "^3.0.1",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "1.0.0",
"mini-css-extract-plugin": "2.7.6",
"node-schedule": "2.1.0",
"ora": "5.4.1",
"outdent": "0.8.0",
"p-map": "4.0.0",
"passport-local": "1.0.0",
"pluralize": "8.0.0",
"prettier": "2.8.4",
"prop-types": "^15.8.1",
"qs": "6.11.1",
"react": "^18.2.0",
@ -153,8 +131,6 @@
"react-router-dom": "5.3.4",
"react-select": "5.7.0",
"react-window": "1.8.8",
"read-pkg-up": "7.0.1",
"resolve-from": "5.0.0",
"rimraf": "3.0.2",
"sanitize-html": "2.11.0",
"semver": "7.5.4",
@ -162,20 +138,14 @@
"slate": "0.94.1",
"slate-history": "0.93.0",
"slate-react": "0.98.3",
"style-loader": "3.3.1",
"styled-components": "5.3.3",
"typescript": "5.3.2",
"webpack": "^5.88.1",
"webpack-bundle-analyzer": "^4.9.0",
"webpack-dev-middleware": "6.1.1",
"webpack-hot-middleware": "2.25.4",
"yup": "0.32.9"
},
"devDependencies": {
"@strapi/admin-test-utils": "4.15.5",
"@strapi/pack-up": "4.15.5",
"@strapi/plugin-content-manager": "4.15.5",
"@strapi/strapi": "4.15.5",
"@testing-library/dom": "9.2.0",
"@testing-library/react": "14.0.0",
"@testing-library/user-event": "14.4.3",
@ -203,7 +173,6 @@
},
"peerDependencies": {
"@strapi/data-transfer": "4.15.5",
"@strapi/strapi": "^4.3.4",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"react-router-dom": "^5.2.0",

View File

@ -13,9 +13,10 @@ const config: Config = defineConfig({
},
{
source: './_internal/index.ts',
import: './dist/cli.mjs',
require: './dist/cli.js',
runtime: 'node',
import: './dist/_internal.mjs',
require: './dist/_internal.js',
types: './dist/_internal/index.d.ts',
runtime: 'web',
},
{
source: './server/src/index.ts',

View File

@ -103,6 +103,7 @@
"watch": "pack-up watch"
},
"dependencies": {
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
"@strapi/admin": "4.15.5",
"@strapi/core": "4.15.5",
"@strapi/data-transfer": "4.15.5",
@ -120,17 +121,41 @@
"@strapi/typescript-utils": "4.15.5",
"@strapi/utils": "4.15.5",
"boxen": "5.1.2",
"browserslist": "^4.22.1",
"browserslist-to-esbuild": "1.2.0",
"chalk": "4.1.2",
"chokidar": "3.5.3",
"cli-table3": "0.6.2",
"commander": "8.3.0",
"copyfiles": "2.4.1",
"css-loader": "^6.8.1",
"dotenv": "14.2.0",
"esbuild": "0.19.2",
"esbuild-loader": "^2.21.0",
"esbuild-register": "3.5.0",
"execa": "5.1.1",
"find-root": "1.1.0",
"fork-ts-checker-webpack-plugin": "8.0.0",
"fs-extra": "10.0.0",
"html-webpack-plugin": "5.5.0",
"inquirer": "8.2.5",
"lodash": "4.17.21",
"mini-css-extract-plugin": "2.7.6",
"ora": "5.4.1",
"outdent": "0.8.0",
"pkg-up": "3.1.0",
"prettier": "2.8.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"read-pkg-up": "7.0.1",
"resolve-from": "5.0.0",
"semver": "7.5.4",
"style-loader": "3.3.1",
"typescript": "5.3.2",
"webpack": "^5.88.1",
"webpack-bundle-analyzer": "^4.9.0",
"webpack-dev-middleware": "6.1.1",
"webpack-hot-middleware": "2.25.4",
"yup": "0.32.9"
},
"devDependencies": {
@ -141,6 +166,10 @@
"eslint-config-custom": "4.15.5",
"tsconfig": "4.15.5"
},
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"engines": {
"node": ">=18.0.0 <=20.x.x",
"npm": ">=6.0.0"

View File

@ -0,0 +1,20 @@
import { build as nodeBuild, BuildOptions } from '../../../node/build';
import { handleUnexpectedError } from '../../../node/core/errors';
interface BuildCLIOptions extends BuildOptions {
/**
* @deprecated use `minify` instead
*/
optimization?: boolean;
}
const build = async (options: BuildCLIOptions) => {
try {
await nodeBuild(options);
} catch (err) {
handleUnexpectedError(err);
}
};
export default build;
export type { BuildCLIOptions };

View File

@ -0,0 +1,24 @@
import { createCommand } from 'commander';
import type { StrapiCommand } from '../../types';
import type { BuildCLIOptions } from './action';
import action from './action';
/**
* `$ strapi build`
*/
const command: StrapiCommand = ({ ctx }) => {
return createCommand('build')
.option('-d, --debug', 'Enable debugging mode with verbose logs', false)
.option('--ignore-prompts', 'Ignore all prompts', false)
.option('--minify', 'Minify the output', true)
.option('--no-optimization', '[deprecated]: use minify instead')
.option('--silent', "Don't log anything", false)
.option('--sourcemap', 'Produce sourcemaps', false)
.option('--stats', 'Print build statistics to the console', false)
.description('Build the strapi admin app')
.action(async (options: BuildCLIOptions) => {
return action({ ...options, ...ctx });
});
};
export default command;

View File

@ -0,0 +1,20 @@
import { develop as nodeDevelop, DevelopOptions } from '../../../node/develop';
import { handleUnexpectedError } from '../../../node/core/errors';
interface DevelopCLIOptions extends DevelopOptions {
/**
* @deprecated
*/
browser?: boolean;
}
const develop = async (options: DevelopCLIOptions) => {
try {
await nodeDevelop(options);
} catch (err) {
handleUnexpectedError(err);
}
};
export default develop;
export type { DevelopCLIOptions };

View File

@ -0,0 +1,33 @@
import { createCommand } from 'commander';
import type { StrapiCommand } from '../../types';
import type { DevelopCLIOptions } from './action';
import action from './action';
/**
* `$ strapi develop`
*/
const command: StrapiCommand = ({ ctx }) => {
return createCommand('develop')
.alias('dev')
.option('-d, --debug', 'Enable debugging mode with verbose logs', false)
.option('--silent', "Don't log anything", false)
.option('--ignore-prompts', 'Ignore all prompts', false)
.option('--polling', 'Watch for file changes in network directories', false)
.option('--watch-admin', 'Watch the admin panel for hot changes', false)
.option(
'--no-build',
'[deprecated]: there is middleware for the server, it is no longer a separate process'
)
.option(
'--watch-admin',
'[deprecated]: there is now middleware for watching, it is no longer a separate process'
)
.option('--browser <name>', '[deprecated]: use open instead')
.option('--open', 'Open the admin in your browser', true)
.description('Start your Strapi application in development mode')
.action(async (options: DevelopCLIOptions) => {
return action({ ...options, ...ctx });
});
};
export default command;

View File

@ -1,14 +0,0 @@
import { watchAdmin } from '@strapi/admin';
import { CLIContext } from '../../types';
interface WatchAdminOptions extends CLIContext {
browser: boolean;
}
export default async ({ browser, logger }: WatchAdminOptions) => {
logger.warn('[@strapi/strapi]: watch-admin is deprecated, please use strapi develop instead');
await watchAdmin({
browser,
});
};

View File

@ -1,15 +0,0 @@
import { createCommand } from 'commander';
import type { StrapiCommand } from '../../types';
import { runAction } from '../../utils/helpers';
import action from './action';
/**
* `$ strapi watch-admin`
*/
const command: StrapiCommand = () => {
return createCommand('watch-admin')
.option('--browser <name>', 'Open the browser', true)
.description('Start the admin development server')
.action(runAction('watch-admin', action));
};
export default command;

View File

@ -21,7 +21,8 @@ import enableTelemetry from './actions/telemetry/enable/command';
import generateTemplates from './actions/templates/generate/command';
import generateTsTypes from './actions/ts/generate-types/command';
import versionCommand from './actions/version/command';
import watchAdminCommand from './actions/watch-admin/command';
import buildCommand from './actions/build-command/command';
import developCommand from './actions/develop/command';
import buildPluginCommand from './actions/plugin/build-command/command';
import watchPluginCommand from './actions/plugin/watch/command';
@ -52,7 +53,8 @@ const strapiCommands = [
generateTemplates,
generateTsTypes,
versionCommand,
watchAdminCommand,
buildCommand,
developCommand,
/**
* Plugins
*/
@ -66,10 +68,6 @@ const buildStrapiCommand = async (argv: string[], command = new Command()) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const dtsCommands = require(require.resolve('@strapi/data-transfer')).commands;
strapiCommands.push(...dtsCommands);
// eslint-disable-next-line @typescript-eslint/no-var-requires, node/no-missing-require
const adminCommands = require(require.resolve('@strapi/admin/cli')).commands;
strapiCommands.push(...adminCommands);
} catch (e) {
// noop
}

View File

@ -1,8 +1,8 @@
import type { CLIContext } from '@strapi/strapi';
import * as tsUtils from '@strapi/typescript-utils';
import type { CLIContext } from '../commands/types';
import { checkRequiredDependencies } from './core/dependencies';
import { getTimer, prettyTime } from './core/timer';
import { createBuildContext } from './createBuildContext';
import { createBuildContext } from './create-build-context';
import { writeStaticClientFiles } from './staticFiles';
import { build as buildWebpack } from './webpack/build';
@ -67,6 +67,7 @@ const build = async ({ logger, cwd, tsconfig, ignorePrompts, ...options }: Build
tsconfig,
options,
});
const contextDuration = timer.end('createBuildContext');
contextSpinner.text = `Building build context (${prettyTime(contextDuration)})`;
contextSpinner.succeed();

View File

@ -1,6 +1,6 @@
import path from 'node:path';
import { convertSystemPathToModulePath, pathExists } from '../core/files';
import { BuildContext } from '../createBuildContext';
import { convertSystemPathToModulePath, pathExists } from './files';
import type { BaseContext } from '../types';
const ADMIN_APP_FILES = ['app.js', 'app.mjs', 'app.ts', 'app.jsx', 'app.tsx'];
@ -8,7 +8,7 @@ interface AdminCustomisations {
config?: {
locales?: string[];
};
bootstrap?: Function;
bootstrap?: (...args: any[]) => any;
}
interface AppFile {
@ -25,7 +25,7 @@ interface AppFile {
const loadUserAppFile = async ({
runtimeDir,
appDir,
}: Pick<BuildContext, 'appDir' | 'runtimeDir'>): Promise<AppFile | undefined> => {
}: Pick<BaseContext, 'appDir' | 'runtimeDir'>): Promise<AppFile | undefined> => {
for (const file of ADMIN_APP_FILES) {
const filePath = path.join(appDir, 'src', 'admin', file);

View File

@ -136,9 +136,9 @@ const checkRequiredDependencies = async ({
*/
await execa(file, args, { cwd, stdio: 'inherit' });
return { didInstall: true };
} else {
return { didInstall: false };
}
return { didInstall: false };
}
if (review.length) {

View File

@ -51,9 +51,9 @@ const loadFile = async (path: string): Promise<undefined | any> => {
const convertSystemPathToModulePath = (sysPath: string) => {
if (process.platform === 'win32') {
return sysPath.split(path.sep).join(path.posix.sep);
} else {
return sysPath;
}
return sysPath;
};
/**
@ -66,9 +66,9 @@ const convertSystemPathToModulePath = (sysPath: string) => {
const convertModulePathToSystemPath = (modulePath: string) => {
if (process.platform === 'win32') {
return modulePath.split(path.posix.sep).join(path.sep);
} else {
return modulePath;
}
return modulePath;
};
export { pathExists, loadFile, convertSystemPathToModulePath, convertModulePathToSystemPath };

View File

@ -5,7 +5,7 @@ import camelCase from 'lodash/camelCase';
import { env } from '@strapi/utils';
import { getModule, PackageJson } from './dependencies';
import { convertModulePathToSystemPath, convertSystemPathToModulePath, loadFile } from './files';
import { BuildContext } from '../createBuildContext';
import type { BaseContext } from '../types';
import { isError } from './errors';
interface LocalPluginMeta {
@ -75,7 +75,7 @@ const getEnabledPlugins = async ({
logger,
runtimeDir,
strapi,
}: Pick<BuildContext, 'cwd' | 'logger' | 'strapi' | 'runtimeDir'>): Promise<
}: Pick<BaseContext, 'cwd' | 'logger' | 'strapi' | 'runtimeDir'>): Promise<
Record<string, PluginMeta>
> => {
const plugins: Record<string, PluginMeta> = {};

View File

@ -31,5 +31,5 @@ export function getTimer(): TimeMeasurer {
}
export const prettyTime = (timeInMs: number): string => {
return Math.ceil(timeInMs) + 'ms';
return `${Math.ceil(timeInMs)}ms`;
};

View File

@ -2,79 +2,36 @@ import os from 'node:os';
import path from 'node:path';
import fs from 'node:fs/promises';
import browserslist from 'browserslist';
import { strapiFactory, CLIContext } from '@strapi/strapi';
import { strapiFactory } from '@strapi/core';
import { getConfigUrls } from '@strapi/utils';
import { Strapi } from '@strapi/types';
import type { CLIContext } from '../commands/types';
import { getStrapiAdminEnvVars, loadEnv } from './core/env';
import type { BuildOptions } from './build';
import { DevelopOptions } from './develop';
import { PluginMeta, getEnabledPlugins, getMapOfPluginsWithAdmin } from './core/plugins';
import { Strapi } from '@strapi/types';
import { AppFile, loadUserAppFile } from './core/admin-customisations';
import type { BaseContext } from './types';
interface BuildContext {
/**
* The absolute path to the app directory defined by the Strapi instance
*/
appDir: string;
/**
* If a user is deploying the project under a nested public path, we use
* this path so all asset paths will be rewritten accordingly
*/
basePath: string;
interface BuildContext<TOptions = unknown> extends BaseContext {
/**
* The customisations defined by the user in their app.js file
*/
customisations?: AppFile;
/**
* The current working directory
*/
cwd: string;
/**
* The absolute path to the dist directory
*/
distPath: string;
/**
* The relative path to the dist directory
*/
distDir: string;
/**
* The absolute path to the entry file
*/
entry: string;
/**
* The environment variables to be included in the JS bundle
*/
env: Record<string, string>;
logger: CLIContext['logger'];
/**
* The build options
*/
options: Pick<BuildOptions, 'minify' | 'sourcemaps' | 'stats'> & Pick<DevelopOptions, 'open'>;
options: TOptions;
/**
* The plugins to be included in the JS bundle
* incl. internal plugins, third party plugins & local plugins
*/
plugins: PluginMeta[];
/**
* The absolute path to the runtime directory
*/
runtimeDir: string;
/**
* The Strapi instance
*/
strapi: Strapi;
/**
* The browserslist target either loaded from the user's workspace or falling back to the default
*/
target: string[];
tsconfig?: CLIContext['tsconfig'];
}
interface CreateBuildContextArgs extends CLIContext {
interface CreateBuildContextArgs<TOptions = unknown> extends CLIContext {
strapi?: Strapi;
options?: BuildContext['options'];
options?: TOptions;
}
const DEFAULT_BROWSERSLIST = [
@ -84,13 +41,13 @@ const DEFAULT_BROWSERSLIST = [
'not dead',
];
const createBuildContext = async ({
const createBuildContext = async <TOptions>({
cwd,
logger,
tsconfig,
strapi,
options = {},
}: CreateBuildContextArgs): Promise<BuildContext> => {
options = {} as TOptions,
}: CreateBuildContextArgs<TOptions>): Promise<BuildContext<TOptions>> => {
/**
* If you make a new strapi instance when one already exists,
* you will overwrite the global and the app will _most likely_
@ -176,7 +133,7 @@ const createBuildContext = async ({
strapi: strapiInstance,
target,
tsconfig,
} satisfies BuildContext;
} satisfies BuildContext<TOptions>;
return buildContext;
};

View File

@ -1,19 +1,18 @@
import type { CLIContext } from '@strapi/strapi';
import * as tsUtils from '@strapi/typescript-utils';
import { joinBy } from '@strapi/utils';
import chokidar from 'chokidar';
import fs from 'node:fs/promises';
import path from 'node:path';
import cluster from 'node:cluster';
import { strapiFactory } from '@strapi/core';
import type { CLIContext } from '../commands/types';
import { checkRequiredDependencies } from './core/dependencies';
import { getTimer, prettyTime, type TimeMeasurer } from './core/timer';
import { createBuildContext } from './createBuildContext';
import { createBuildContext } from './create-build-context';
import { build as buildWebpack } from './webpack/build';
import { watch as watchWebpack, WebpackWatcher } from './webpack/watch';
import { strapiFactory } from '@strapi/strapi';
import { writeStaticClientFiles } from './staticFiles';
interface DevelopOptions extends CLIContext {
@ -44,7 +43,7 @@ const cleanupDistDirectory = async ({
return;
}
const timerName = 'cleaningDist' + Date.now();
const timerName = `cleaningDist${Date.now()}`;
timer.start(timerName);
const cleaningSpinner = logger.spinner(`Cleaning dist dir ${distDir}`).start();

View File

@ -4,10 +4,9 @@ import outdent from 'outdent';
import { format } from 'prettier';
import { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import camelCase from 'lodash/camelCase';
import { DefaultDocument as Document } from '../../admin/src/components/DefaultDocument';
import { DefaultDocument } from '@strapi/admin/_internal';
import type { BuildContext } from './createBuildContext';
import type { BuildContext } from './create-build-context';
const getEntryModule = (ctx: BuildContext): string => {
const pluginsObject = ctx.plugins
@ -48,7 +47,7 @@ const getEntryModule = (ctx: BuildContext): string => {
* to load a user's Document component?
*/
const getDocumentHTML = async ({ logger }: Pick<BuildContext, 'logger'>) => {
const result = renderToStaticMarkup(createElement(Document));
const result = renderToStaticMarkup(createElement(DefaultDocument));
logger.debug('Rendered the HTML');
return outdent`<!DOCTYPE html>${result}`;

View File

@ -0,0 +1,53 @@
import { Strapi } from '@strapi/types';
import type { CLIContext } from '../commands/types';
interface BaseContext {
/**
* The absolute path to the app directory defined by the Strapi instance
*/
appDir: string;
/**
* If a user is deploying the project under a nested public path, we use
* this path so all asset paths will be rewritten accordingly
*/
basePath: string;
/**
* The current working directory
*/
cwd: string;
/**
* The absolute path to the dist directory
*/
distPath: string;
/**
* The relative path to the dist directory
*/
distDir: string;
/**
* The absolute path to the entry file
*/
entry: string;
/**
* The environment variables to be included in the JS bundle
*/
env: Record<string, string>;
logger: CLIContext['logger'];
/**
* The absolute path to the runtime directory
*/
runtimeDir: string;
/**
* The Strapi instance
*/
strapi: Strapi;
/**
* The browserslist target either loaded from the user's workspace or falling back to the default
*/
target: string[];
tsconfig?: CLIContext['tsconfig'];
}
export type { BaseContext };

View File

@ -3,15 +3,15 @@ import webpack from 'webpack';
import { mergeConfigWithUserConfig, resolveProductionConfig } from './config';
import { isError } from '../core/errors';
import type { BuildContext } from '../createBuildContext';
import type { BuildContext } from '../create-build-context';
const build = async (ctx: BuildContext) =>
new Promise(async (resolve, reject) => {
const config = await resolveProductionConfig(ctx);
const finalConfig = await mergeConfigWithUserConfig(config, ctx);
const build = async (ctx: BuildContext) => {
const config = await resolveProductionConfig(ctx);
const finalConfig = await mergeConfigWithUserConfig(config, ctx);
ctx.logger.debug('Webpack config', finalConfig);
ctx.logger.debug('Webpack config', finalConfig);
return new Promise((resolve, reject) => {
webpack(finalConfig, (err, stats) => {
if (stats) {
if (stats.hasErrors()) {
@ -22,7 +22,7 @@ const build = async (ctx: BuildContext) =>
})
);
reject(false);
reject();
} else if (ctx.options.stats) {
ctx.logger.info(
stats.toString({
@ -37,9 +37,10 @@ const build = async (ctx: BuildContext) =>
if (err && isError(err)) {
ctx.logger.error(err.message);
reject(false);
reject();
}
});
});
};
export { build };

View File

@ -16,7 +16,7 @@ import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import { loadFile } from '../core/files';
import { loadStrapiMonorepo } from '../core/monorepo';
import type { BuildContext } from '../createBuildContext';
import type { BuildContext } from '../create-build-context';
import { getAliases } from './aliases';
const resolveBaseConfig = async (ctx: BuildContext) => {
@ -225,16 +225,16 @@ const mergeConfigWithUserConfig = async (config: Configuration, ctx: BuildContex
if (typeof userConfig === 'function') {
const webpack = await import('webpack');
return userConfig(config, webpack);
} else {
ctx.logger.warn(
`You've exported something other than a function from ${path.join(
ctx.appDir,
'src',
'admin',
'webpack.config'
)}, this will ignored.`
);
}
ctx.logger.warn(
`You've exported something other than a function from ${path.join(
ctx.appDir,
'src',
'admin',
'webpack.config'
)}, this will ignored.`
);
}
return config;

View File

@ -4,9 +4,9 @@ import { promisify } from 'node:util';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import { webpack } from 'webpack';
import type { BuildContext } from '../createBuildContext';
import { Common } from '@strapi/types';
import type { BuildContext } from '../create-build-context';
import { mergeConfigWithUserConfig, resolveDevelopmentConfig } from './config';
import { Common, Strapi } from '@strapi/types';
interface WebpackWatcher {
close(): Promise<void>;
@ -23,7 +23,7 @@ const watch = async (ctx: BuildContext): Promise<WebpackWatcher> => {
const devMiddleware = webpackDevMiddleware(compiler);
// @ts-ignore
// @ts-expect-error ignored
const hotMiddleware = webpackHotMiddleware(compiler, {
log: false,
path: '/__webpack_hmr',
@ -40,7 +40,7 @@ const watch = async (ctx: BuildContext): Promise<WebpackWatcher> => {
ctx.strapi.server.app.use((context, next) => {
// wait for webpack-dev-middleware to signal that the build is ready
const ready = new Promise((resolve, reject) => {
const ready = new Promise((resolve) => {
devMiddleware.waitUntilValid(() => {
resolve(true);
});
@ -50,14 +50,14 @@ const watch = async (ctx: BuildContext): Promise<WebpackWatcher> => {
devMiddleware(
context.req,
{
// @ts-expect-error
end: (content) => {
// @ts-expect-error ignored
end(content) {
// eslint-disable-next-line no-param-reassign
context.body = content;
resolve(true);
},
getHeader: context.get.bind(context),
// @ts-expect-error
// @ts-expect-error ignored
setHeader: context.set.bind(context),
locals: context.state,
},
@ -80,6 +80,7 @@ const watch = async (ctx: BuildContext): Promise<WebpackWatcher> => {
return;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
const filename = path.resolve(finalConfig.output?.path!, 'index.html');
ctx.type = 'html';
ctx.body = devMiddleware.context.outputFileSystem.createReadStream(filename);

View File

@ -1,7 +1,8 @@
{
"extends": "tsconfig/base.json",
"compilerOptions": {
"noEmit": true
"noEmit": true,
"rootDir": "./src"
},
"include": ["src"],
"exclude": ["node_modules"]

View File

@ -8572,7 +8572,6 @@ __metadata:
resolution: "@strapi/admin@workspace:packages/core/admin"
dependencies:
"@casl/ability": "npm:6.5.0"
"@pmmmwh/react-refresh-webpack-plugin": "npm:0.5.10"
"@radix-ui/react-context": "npm:1.0.1"
"@radix-ui/react-toolbar": "npm:1.0.4"
"@reduxjs/toolkit": "npm:1.9.7"
@ -8585,7 +8584,6 @@ __metadata:
"@strapi/permissions": "npm:4.15.5"
"@strapi/plugin-content-manager": "npm:4.15.5"
"@strapi/provider-audit-logs-local": "npm:4.15.5"
"@strapi/strapi": "npm:4.15.5"
"@strapi/types": "npm:4.15.5"
"@strapi/typescript-utils": "npm:4.15.5"
"@strapi/utils": "npm:4.15.5"
@ -8614,28 +8612,17 @@ __metadata:
axios: "npm:1.6.0"
bcryptjs: "npm:2.4.3"
boxen: "npm:5.1.2"
browserslist: "npm:^4.22.1"
browserslist-to-esbuild: "npm:1.2.0"
chalk: "npm:^4.1.2"
chokidar: "npm:3.5.3"
codemirror5: "npm:codemirror@^5.65.11"
cross-env: "npm:^7.0.3"
css-loader: "npm:^6.8.1"
date-fns: "npm:2.30.0"
dotenv: "npm:14.2.0"
esbuild: "npm:0.19.2"
esbuild-loader: "npm:^2.21.0"
esbuild-register: "npm:3.5.0"
execa: "npm:5.1.1"
fast-deep-equal: "npm:3.1.3"
find-root: "npm:1.1.0"
fork-ts-checker-webpack-plugin: "npm:8.0.0"
formik: "npm:2.4.0"
fractional-indexing: "npm:3.2.0"
fs-extra: "npm:10.0.0"
highlight.js: "npm:^10.4.1"
history: "npm:^4.9.0"
html-webpack-plugin: "npm:5.5.0"
immer: "npm:9.0.19"
inquirer: "npm:8.2.5"
invariant: "npm:^2.2.4"
@ -8658,15 +8645,12 @@ __metadata:
markdown-it-mark: "npm:^3.0.1"
markdown-it-sub: "npm:^1.0.0"
markdown-it-sup: "npm:1.0.0"
mini-css-extract-plugin: "npm:2.7.6"
msw: "npm:1.3.0"
node-schedule: "npm:2.1.0"
ora: "npm:5.4.1"
outdent: "npm:0.8.0"
p-map: "npm:4.0.0"
passport-local: "npm:1.0.0"
pluralize: "npm:8.0.0"
prettier: "npm:2.8.4"
prop-types: "npm:^15.8.1"
qs: "npm:6.11.1"
react: "npm:^18.2.0"
@ -8683,8 +8667,6 @@ __metadata:
react-router-dom: "npm:5.3.4"
react-select: "npm:5.7.0"
react-window: "npm:1.8.8"
read-pkg-up: "npm:7.0.1"
resolve-from: "npm:5.0.0"
rimraf: "npm:3.0.2"
sanitize-html: "npm:2.11.0"
semver: "npm:7.5.4"
@ -8692,18 +8674,12 @@ __metadata:
slate: "npm:0.94.1"
slate-history: "npm:0.93.0"
slate-react: "npm:0.98.3"
style-loader: "npm:3.3.1"
styled-components: "npm:5.3.3"
typescript: "npm:5.3.2"
vite: "npm:4.4.9"
webpack: "npm:^5.88.1"
webpack-bundle-analyzer: "npm:^4.9.0"
webpack-dev-middleware: "npm:6.1.1"
webpack-hot-middleware: "npm:2.25.4"
yup: "npm:0.32.9"
peerDependencies:
"@strapi/data-transfer": 4.15.5
"@strapi/strapi": ^4.3.4
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
react-router-dom: ^5.2.0
@ -9583,6 +9559,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@strapi/strapi@workspace:packages/core/strapi"
dependencies:
"@pmmmwh/react-refresh-webpack-plugin": "npm:0.5.10"
"@strapi/admin": "npm:4.15.5"
"@strapi/core": "npm:4.15.5"
"@strapi/data-transfer": "npm:4.15.5"
@ -9603,20 +9580,47 @@ __metadata:
"@types/lodash": "npm:^4.14.191"
"@types/node": "npm:18.18.4"
boxen: "npm:5.1.2"
browserslist: "npm:^4.22.1"
browserslist-to-esbuild: "npm:1.2.0"
chalk: "npm:4.1.2"
chokidar: "npm:3.5.3"
cli-table3: "npm:0.6.2"
commander: "npm:8.3.0"
copyfiles: "npm:2.4.1"
css-loader: "npm:^6.8.1"
dotenv: "npm:14.2.0"
esbuild: "npm:0.19.2"
esbuild-loader: "npm:^2.21.0"
esbuild-register: "npm:3.5.0"
eslint-config-custom: "npm:4.15.5"
execa: "npm:5.1.1"
find-root: "npm:1.1.0"
fork-ts-checker-webpack-plugin: "npm:8.0.0"
fs-extra: "npm:10.0.0"
html-webpack-plugin: "npm:5.5.0"
inquirer: "npm:8.2.5"
lodash: "npm:4.17.21"
mini-css-extract-plugin: "npm:2.7.6"
ora: "npm:5.4.1"
outdent: "npm:0.8.0"
pkg-up: "npm:3.1.0"
prettier: "npm:2.8.4"
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"
read-pkg-up: "npm:7.0.1"
resolve-from: "npm:5.0.0"
semver: "npm:7.5.4"
style-loader: "npm:3.3.1"
tsconfig: "npm:4.15.5"
typescript: "npm:5.3.2"
webpack: "npm:^5.88.1"
webpack-bundle-analyzer: "npm:^4.9.0"
webpack-dev-middleware: "npm:6.1.1"
webpack-hot-middleware: "npm:2.25.4"
yup: "npm:0.32.9"
peerDependencies:
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
bin:
strapi: ./bin/strapi.js
languageName: unknown