@elsikora/setup-wizard
Version:
Setup Wizard - CLI scaffolding utility
564 lines (553 loc) • 19.2 kB
JavaScript
#!/usr/bin/env node
import path from 'node:path';
import { EBuildTool } from '../../../domain/enum/build-tool.enum.js';
import { BUILDER_TYPESCRIPT_PACKAGE_NAME, BUILDER_WEBPACK_PACKAGE_NAME, BUILDER_WEBPACK_CLI_PACKAGE_NAME, BUILDER_VITE_TSCONFIG_PATHS_PACKAGE_NAME, BUILDER_VITE_PACKAGE_NAME, BUILDER_TURBOPACK_PACKAGE_NAME, BUILDER_SWC_CORE_PACKAGE_NAME, BUILDER_SWC_CLI_PACKAGE_NAME, BUILDER_ROLLUP_PLUGIN_TYPESCRIPT, BUILDER_TSLIB_PACKAGE_NAME, BUILDER_ROLLUP_PLUGIN_DTS_PATH_ALIAS, BUILDER_ROLLUP_PLUGIN_TERSER, BUILDER_ROLLUP_PACKAGE_NAME, BUILDER_PARCEL_PACKAGE_NAME, BUILDER_ESBUILD_PACKAGE_NAME } from './package-names.constant.js';
/**
* Configuration for different build tools.
* Provides tool-specific settings and dependencies.
*/
const BUILD_TOOL_CONFIG = {
[EBuildTool.ESBUILD]: {
canSupportCliApps: true,
configFileName: "esbuild.config.js",
configGenerator: (options) => {
const { entryPoint, formats, isCliApp, isMinifyEnabled, isSourceMapsEnabled, isTypeScript, outputDirectory } = options;
// esbuild uses a JavaScript config file
const format = formats[0]; // esbuild builds one format at a time
let outExtension;
if (format === "esm") {
outExtension = ".mjs";
}
else if (format === "cjs") {
outExtension = ".cjs";
}
else {
outExtension = ".js";
}
// Extract nested ternary for format
let buildFormat;
if (format === "esm") {
buildFormat = "esm";
}
else if (format === "cjs") {
buildFormat = "cjs";
}
else {
buildFormat = "iife";
}
return `import { build } from "esbuild";
import { resolve } from "path";
const args = process.argv.slice(2);
const isWatch = args.includes("--watch");
const buildOptions = {
entryPoints: ["${entryPoint}"],
bundle: true,
platform: "${isCliApp ? "node" : "neutral"}",
format: "${buildFormat}",
outfile: "${outputDirectory}/${path.basename(entryPoint, path.extname(entryPoint))}${outExtension}",
sourcemap: ${isSourceMapsEnabled},
minify: ${isMinifyEnabled},${isCliApp
? `
banner: {
js: "#!/usr/bin/env node",
},`
: ""}${isTypeScript
? `
tsconfig: "./tsconfig.json",`
: ""}
external: ${isCliApp ? '["node:*"]' : "[]"},
};
if (isWatch) {
const context = await build({ ...buildOptions, metafile: true });
await context.watch();
console.log("Watching for changes...");
} else {
await build(buildOptions);
console.log("Build complete!");
}
`;
},
coreDependencies: [BUILDER_ESBUILD_PACKAGE_NAME],
defaultOutputDir: "./dist",
defaultOutputDirCli: "./bin",
description: "An extremely fast JavaScript bundler",
name: "esbuild",
optionalDependencies: {
minify: [], // Built-in
typescript: [BUILDER_TYPESCRIPT_PACKAGE_NAME],
},
scripts: {
build: "node esbuild.config.js",
dev: "node esbuild.config.js --watch",
watch: "node esbuild.config.js --watch",
},
supportedFormats: ["esm", "cjs", "iife"],
},
[EBuildTool.PARCEL]: {
canSupportCliApps: true,
configFileName: ".parcelrc",
configGenerator: (_options) => {
// Parcel uses .parcelrc for configuration
return `{
"extends": "@parcel/config-default",
"transformers": {
"*.{js,jsx,ts,tsx}": ["@parcel/transformer-js"]
}
}
`;
},
coreDependencies: [BUILDER_PARCEL_PACKAGE_NAME],
defaultOutputDir: "./dist",
defaultOutputDirCli: "./bin",
description: "The zero configuration build tool",
name: "Parcel",
optionalDependencies: {
minify: [], // Built-in
typescript: [BUILDER_TYPESCRIPT_PACKAGE_NAME],
},
scripts: {
build: "parcel build",
dev: "parcel watch",
watch: "parcel watch",
},
supportedFormats: ["esm", "cjs"],
},
[EBuildTool.ROLLUP]: {
canSupportCliApps: true,
configFileName: "rollup.config.js",
configGenerator: (options) => {
const { entryPoint, formats, isCliApp, isCommonjsEnabled, isDecoratorsEnabled, isMinifyEnabled, isPackageJsonGenerationEnabled, isPathAliasEnabled, isSourceMapsEnabled, isTypeScript, outputDirectory, } = options;
const imports = [];
// Base imports
imports.push("import resolve from '@rollup/plugin-node-resolve';");
// CommonJS plugin (only if enabled)
if (isCommonjsEnabled) {
imports.push("import commonjs from '@rollup/plugin-commonjs';");
}
// TypeScript plugin
if (isTypeScript) {
imports.push("import typescript from '@rollup/plugin-typescript';");
}
// Optional plugins
if (isPathAliasEnabled) {
imports.push("import dtsPathAlias from 'rollup-plugin-dts-path-alias';");
}
if (isMinifyEnabled) {
imports.push("import terser from '@rollup/plugin-terser';");
}
if (isPackageJsonGenerationEnabled && !isCliApp) {
imports.push("import generatePackageJson from 'rollup-plugin-generate-package-json';");
}
// Generate configurations for each format
if (isCliApp || formats.length === 1) {
// Single configuration
const format = formats[0];
const plugins = [];
// Resolve plugin with decorators support
if (isDecoratorsEnabled) {
plugins.push(`resolve({
include: ["node_modules/tslib/**"],
})`);
}
else {
plugins.push("resolve()");
}
if (isCommonjsEnabled) {
plugins.push("commonjs()");
}
if (isPathAliasEnabled) {
plugins.push("dtsPathAlias()");
}
if (isTypeScript) {
const tsconfigPath = isCliApp ? "./tsconfig.json" : "./tsconfig.build.json";
plugins.push(`typescript({
declaration: true,
outDir: "${outputDirectory}",
sourceMap: ${isSourceMapsEnabled},
tsconfig: "${tsconfigPath}",
})`);
}
if (isMinifyEnabled) {
plugins.push("terser()");
}
const outputOptions = [];
if (isCliApp) {
outputOptions.push(`banner: "#!/usr/bin/env node"`);
}
// Determine output file/dir
const baseName = path.basename(entryPoint, path.extname(entryPoint));
if (isCliApp) {
outputOptions.push(`dir: "${outputDirectory}"`, `preserveModules: true`, `preserveModulesRoot: "src"`);
}
else {
let extension;
if (format === "esm") {
extension = "mjs";
}
else if (format === "cjs") {
extension = "cjs";
}
else {
extension = "js";
}
outputOptions.push(`file: "${outputDirectory}/${baseName}.${extension}"`);
}
outputOptions.push(`format: "${format === "cjs" ? "cjs" : format}"`);
if (format === "cjs") {
outputOptions.push(`exports: "named"`);
}
else if (isCliApp && format === "esm") {
outputOptions.push(`exports: "auto"`);
}
outputOptions.push(`sourcemap: ${isSourceMapsEnabled}`);
return `${imports.join("\n")}
export default {
${isCliApp ? 'external: ["node:fs", "node:fs/promises", "node:path", "node:child_process", "node:util"],\n\t' : ""}input: "${entryPoint}",
output: {
${outputOptions.join(",\n\t\t")}
},
plugins: [
${plugins.join(",\n\t\t")}
],
};
`;
}
else {
// Multiple configurations for different formats
const configs = [];
for (const format of formats) {
const outputDirectoryFormat = `${outputDirectory}/${format}`;
const plugins = [];
// Resolve plugin with decorators support
if (isDecoratorsEnabled) {
plugins.push(`resolve({
include: ["node_modules/tslib/**"],
})`);
}
else {
plugins.push("resolve()");
}
if (isCommonjsEnabled) {
plugins.push("commonjs()");
}
if (isPathAliasEnabled) {
plugins.push("dtsPathAlias()");
}
if (isTypeScript) {
plugins.push(`typescript({
declaration: true,
declarationDir: "${outputDirectoryFormat}",
outDir: "${outputDirectoryFormat}",
sourceMap: ${isSourceMapsEnabled},
tsconfig: "./tsconfig.build.json",
})`);
}
if (isMinifyEnabled) {
plugins.push("terser()");
}
if (isPackageJsonGenerationEnabled) {
const packageType = format === "esm" ? "module" : "commonjs";
plugins.push(`generatePackageJson({
baseContents: { type: "${packageType}" },
outputFolder: "${outputDirectoryFormat}",
})`);
}
const entryFileNamesFunction = isDecoratorsEnabled
? `entryFileNames: (chunkInfo) => {
if (chunkInfo.name.includes("node_modules")) {
return chunkInfo.name.replace("node_modules", "external") + ".js";
}
return "[name].js";
},`
: "";
configs.push(`{
input: "${entryPoint}",
output: {
dir: "${outputDirectoryFormat}",
${entryFileNamesFunction}
${format === "cjs" ? 'exports: "named",\n\t\t\t' : ""}format: "${format}",
preserveModules: true,
preserveModulesRoot: "src",
sourcemap: ${isSourceMapsEnabled},
},
plugins: [
${plugins.join(",\n\t\t\t")}
],
}`);
}
return `${imports.join("\n")}
export default [
${configs.join(",\n\t")}
];
`;
}
},
coreDependencies: [BUILDER_ROLLUP_PACKAGE_NAME],
defaultOutputDir: "./dist",
defaultOutputDirCli: "./bin",
description: "Next-generation ES module bundler",
name: "Rollup",
optionalDependencies: {
decorators: [BUILDER_TSLIB_PACKAGE_NAME],
minify: [BUILDER_ROLLUP_PLUGIN_TERSER],
pathAlias: [BUILDER_ROLLUP_PLUGIN_DTS_PATH_ALIAS],
typescript: [BUILDER_ROLLUP_PLUGIN_TYPESCRIPT, BUILDER_TSLIB_PACKAGE_NAME],
},
scripts: {
build: "rollup -c",
dev: "rollup -c -w",
watch: "rollup -c -w",
},
supportedFormats: ["esm", "cjs", "umd", "iife"],
},
[EBuildTool.SWC]: {
canSupportCliApps: true,
configFileName: ".swcrc",
configGenerator: (options) => {
const { isDecoratorsEnabled, isMinifyEnabled, isSourceMapsEnabled } = options;
// SWC uses .swcrc for configuration
return `{
"$schema": "https://json.schemastore.org/swcrc",
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": ${isDecoratorsEnabled}
},
"target": "es2022",
"loose": false,
"minify": ${isMinifyEnabled
? `{
"compress": true,
"mangle": true
}`
: "null"}
},
"module": {
"type": "es6"
},
"minify": ${isMinifyEnabled},
"sourceMaps": ${isSourceMapsEnabled}
}
`;
},
coreDependencies: [BUILDER_SWC_CORE_PACKAGE_NAME, BUILDER_SWC_CLI_PACKAGE_NAME],
defaultOutputDir: "./dist",
defaultOutputDirCli: "./bin",
description: "Super-fast TypeScript/JavaScript compiler",
name: "SWC",
optionalDependencies: {
minify: [], // Built-in
typescript: [], // Built-in
},
scripts: {
build: "swc src -d dist",
dev: "swc src -d dist --watch",
watch: "swc src -d dist --watch",
},
supportedFormats: ["esm", "cjs"],
},
[EBuildTool.TURBOPACK]: {
canSupportCliApps: true,
configFileName: "turbopack.config.js",
configGenerator: (options) => {
const { entryPoint, isMinifyEnabled, isSourceMapsEnabled, outputDirectory } = options;
// Turbopack uses a JavaScript config
return `export default {
entry: {
main: "${entryPoint}",
},
output: {
path: "${outputDirectory}",
filename: "[name].js",
},
optimization: {
minimize: ${isMinifyEnabled},
},
devtool: ${isSourceMapsEnabled ? '"source-map"' : "false"},
};
`;
},
coreDependencies: [BUILDER_TURBOPACK_PACKAGE_NAME],
defaultOutputDir: "./dist",
defaultOutputDirCli: "./bin",
description: "Incremental bundler optimized for JavaScript and TypeScript",
name: "Turbopack",
optionalDependencies: {
minify: [],
typescript: [BUILDER_TYPESCRIPT_PACKAGE_NAME],
},
scripts: {
build: "turbopack build",
dev: "turbopack dev",
watch: "turbopack dev",
},
supportedFormats: ["esm", "cjs"],
},
[EBuildTool.VITE]: {
canSupportCliApps: false,
configFileName: "vite.config.js",
configGenerator: (options) => {
const { entryPoint, formats, isMinifyEnabled, isPathAliasEnabled, isSourceMapsEnabled, isTypeScript, outputDirectory } = options;
const plugins = [];
if (isPathAliasEnabled && isTypeScript) {
plugins.push("viteTsconfigPaths()");
}
const formatMap = {
esm: "es",
umd: "umd",
};
return `import { defineConfig } from "vite";
import { resolve } from "path";${isPathAliasEnabled && isTypeScript
? `
import viteTsconfigPaths from "vite-tsconfig-paths";`
: ""}
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, "${entryPoint}"),
name: "MyLib",
formats: ${JSON.stringify(formats.map((f) => formatMap[f] || f))},
fileName: (format) => \`index.\${format}.js\`,
},
outDir: "${outputDirectory}",
sourcemap: ${isSourceMapsEnabled},
minify: ${isMinifyEnabled ? '"esbuild"' : "false"},
rollupOptions: {
external: [],
output: {
globals: {},
},
},
},${plugins.length > 0
? `
plugins: [${plugins.join(", ")}],`
: ""}
});
`;
},
coreDependencies: [BUILDER_VITE_PACKAGE_NAME],
defaultOutputDir: "./dist",
defaultOutputDirCli: "./bin",
description: "Next generation frontend tooling",
name: "Vite",
optionalDependencies: {
minify: [], // Built-in
pathAlias: [BUILDER_VITE_TSCONFIG_PATHS_PACKAGE_NAME],
typescript: [], // Built-in
},
scripts: {
build: "vite build",
dev: "vite",
watch: "vite build --watch",
},
supportedFormats: ["esm", "umd"],
},
[EBuildTool.WEBPACK]: {
canSupportCliApps: true,
configFileName: "webpack.config.js",
configGenerator: (options) => {
const { entryPoint, formats, isCliApp, isMinifyEnabled, isPathAliasEnabled, isSourceMapsEnabled, isTypeScript, outputDirectory } = options;
const rules = [];
const plugins = [];
const imports = ["const path = require('path');"];
if (isTypeScript) {
rules.push(`{
test: /\\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
}`);
}
if (isMinifyEnabled) {
imports.push("const TerserPlugin = require('terser-webpack-plugin');");
}
if (isPathAliasEnabled && isTypeScript) {
imports.push("const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');");
}
// Webpack output format mapping
const firstFormat = formats[0];
let libraryType;
if (firstFormat === "commonjs") {
libraryType = "commonjs2";
}
else if (firstFormat === "module") {
libraryType = "module";
}
else {
libraryType = "umd";
}
return `${imports.join("\n")}
module.exports = {
entry: '${entryPoint}',
mode: 'production',
devtool: ${isSourceMapsEnabled ? "'source-map'" : "false"},${isCliApp
? `
target: 'node',`
: ""}
module: {
rules: [${rules.length > 0
? `
${rules.join(",\n\t\t\t")}`
: ""}
],
},${(() => {
if (isPathAliasEnabled && isTypeScript) {
return `
resolve: {
extensions: ['.tsx', '.ts', '.js'],
plugins: [new TsconfigPathsPlugin()],
},`;
}
else if (isTypeScript) {
return `
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},`;
}
else {
return "";
}
})()}
output: {
filename: 'index.js',
path: path.resolve(__dirname, '${outputDirectory}'),
library: {
type: '${libraryType}',
},${isCliApp
? `
hashbang: true,`
: ""}
},${isMinifyEnabled
? `
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},`
: ""}${plugins.length > 0
? `
plugins: [
${plugins.join(",\n\t\t")}
],`
: ""}
};
`;
},
coreDependencies: [BUILDER_WEBPACK_PACKAGE_NAME, BUILDER_WEBPACK_CLI_PACKAGE_NAME],
defaultOutputDir: "./dist",
defaultOutputDirCli: "./bin",
description: "Static module bundler for modern JavaScript applications",
name: "Webpack",
optionalDependencies: {
minify: [], // Built-in
typescript: [BUILDER_TYPESCRIPT_PACKAGE_NAME],
},
scripts: {
build: "webpack --mode production",
dev: "webpack --mode development --watch",
watch: "webpack --mode development --watch",
},
supportedFormats: ["esm", "cjs", "umd"],
},
};
export { BUILD_TOOL_CONFIG };
//# sourceMappingURL=build-tool-config.constant.js.map