diff --git a/packages/code-infra/src/cli/cmdBuild.mjs b/packages/code-infra/src/cli/cmdBuild.mjs index 931598b0f..e371ec9b1 100644 --- a/packages/code-infra/src/cli/cmdBuild.mjs +++ b/packages/code-infra/src/cli/cmdBuild.mjs @@ -3,7 +3,7 @@ import { $ } from 'execa'; import set from 'lodash-es/set.js'; import * as fs from 'node:fs/promises'; import * as path from 'node:path'; -import { getOutExtension, isMjsBuild } from '../utils/build.mjs'; +import { getOutExtension, isMjsBuild, validatePkgJson } from '../utils/build.mjs'; /** * @typedef {Object} Args @@ -16,6 +16,7 @@ import { getOutExtension, isMjsBuild } from '../utils/build.mjs'; * @property {boolean} skipTsc - Whether to build types for the package. * @property {boolean} skipBabelRuntimeCheck - Whether to skip checking for Babel runtime dependencies in the package. * @property {boolean} skipPackageJson - Whether to skip generating the package.json file in the bundle output. + * @property {boolean} skipMainCheck - Whether to skip checking for main field in package.json. * @property {string[]} ignore - Globs to be ignored by Babel. */ @@ -291,6 +292,12 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({ type: 'boolean', default: false, description: 'Skip generating the package.json file in the bundle output.', + }) + .option('skipMainCheck', { + // Currently added only to support @mui/icons-material. To be removed separately. + type: 'boolean', + default: false, + description: 'Skip checking for main field in package.json.', }); }, async handler(args) { @@ -310,17 +317,9 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({ const cwd = process.cwd(); const pkgJsonPath = path.join(cwd, 'package.json'); const packageJson = JSON.parse(await fs.readFile(pkgJsonPath, { encoding: 'utf8' })); - const buildDirBase = packageJson.publishConfig?.directory; - if (!buildDirBase) { - throw new Error( - `No build directory specified in "${packageJson.name}" package.json. Specify it in the "publishConfig.directory" field.`, - ); - } - if (packageJson.private === false) { - throw new Error( - `Remove the field "private": false from "${packageJson.name}" package.json. This is redundant.`, - ); - } + validatePkgJson(packageJson, { skipMainCheck: args.skipMainCheck }); + + const buildDirBase = /** @type {string} */ (packageJson.publishConfig?.directory); const buildDir = path.join(cwd, buildDirBase); console.log(`Selected output directory: "${buildDirBase}"`); diff --git a/packages/code-infra/src/utils/build.mjs b/packages/code-infra/src/utils/build.mjs index abb162923..0e3927fc1 100644 --- a/packages/code-infra/src/utils/build.mjs +++ b/packages/code-infra/src/utils/build.mjs @@ -18,3 +18,53 @@ export function getOutExtension(bundle, isType = false) { } return bundle === 'esm' ? '.mjs' : '.js'; } + +/** + * Validates the package.json before building. + * @param {Record} packageJson + * @param {Object} [options] + * @param {boolean} [options.skipMainCheck=false] - Whether to skip checking for main field in package.json. + */ +export function validatePkgJson(packageJson, options = {}) { + const { skipMainCheck = false } = options; + /** + * @type {string[]} + */ + const errors = []; + const buildDirBase = packageJson.publishConfig?.directory; + if (!buildDirBase) { + errors.push( + `No build directory specified in "${packageJson.name}" package.json. Specify it in the "publishConfig.directory" field.`, + ); + } + if (packageJson.private === false) { + errors.push( + `Remove the field "private": false from "${packageJson.name}" package.json. This is redundant.`, + ); + } + + if (!skipMainCheck) { + if (packageJson.main) { + errors.push( + `Remove the field "main" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`, + ); + } + + if (packageJson.module) { + errors.push( + `Remove the field "module" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`, + ); + } + + if (packageJson.types || packageJson.typings) { + errors.push( + `Remove the field "types/typings" from "${packageJson.name}" package.json. Add it as "exports["."]" instead.`, + ); + } + } + + if (errors.length > 0) { + const error = new Error(errors.join('\n')); + throw error; + } +}