create-webpack-starter 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026, Razerspine
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # create-webpack-starter
2
+
3
+ Create a modern webpack project using ready-to-use templates.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npx create-webpack-starter my-app
9
+ ```
10
+
11
+ With options:
12
+
13
+ ```bash
14
+ npx create-webpack-starter my-app \
15
+ --template pug-scss-ts \
16
+ --no-install
17
+ ```
18
+
19
+ ## Options
20
+
21
+ | Option | Description |
22
+ | ------------------- | ------------------------------- |
23
+ | `--template <name>` | Skip prompt and select template |
24
+ | `--no-install` | Skip dependency installation |
25
+ | `--dry-run` | Show what would be done |
26
+
27
+ ## Available templates
28
+ * pug-less-js
29
+ * pug-less-ts
30
+ * pug-scss-js
31
+ * pug-scss-ts
32
+
33
+ ## Requirement
34
+ * Node.js >= 18
35
+ * npm/ pnpm/ yarn
36
+
37
+ ## How it works
38
+ 1. CLI copies the selected template
39
+ 2. Template files are written to the target directory
40
+ 3. Dependencies are installed (unless disabled)
41
+ 4. Project is ready to use
42
+
43
+ ## What you get
44
+ - Preconfigured webpack setup
45
+ - Pug templates
46
+ - SCSS / Less
47
+ - JavaScript or TypeScript
48
+ - Production-ready build
49
+
50
+ ## 📄 License
51
+ This project is licensed under the ISC License.
package/bin/index.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../dist/index.js');
package/dist/cli.js ADDED
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getCliContext = getCliContext;
7
+ const commander_1 = require("commander");
8
+ const inquirer_1 = __importDefault(require("inquirer"));
9
+ const templates_1 = require("./templates");
10
+ async function getCliContext() {
11
+ const program = new commander_1.Command();
12
+ program
13
+ .argument('[project-name]', 'Project name')
14
+ .option('-t, --template <template>', 'Template name')
15
+ .option('--no-install', 'Skip npm install')
16
+ .option('--dry-run', 'Do not write files');
17
+ program.parse(process.argv);
18
+ const options = program.opts();
19
+ let projectName = program.args[0];
20
+ // --- ASK PROJECT NAME IF NOT PROVIDED
21
+ if (!projectName) {
22
+ const answer = await inquirer_1.default.prompt([
23
+ {
24
+ type: 'input',
25
+ name: 'projectName',
26
+ message: 'Project name:',
27
+ validate: v => !!v || 'Project name is required'
28
+ }
29
+ ]);
30
+ projectName = answer.projectName;
31
+ }
32
+ let template = options.template;
33
+ // --- ASK TEMPLATE IF NOT PROVIDED
34
+ if (!template) {
35
+ const answer = await inquirer_1.default.prompt([
36
+ {
37
+ type: 'list',
38
+ name: 'template',
39
+ message: 'Choose a template:',
40
+ choices: Object.values(templates_1.templates).map(t => ({
41
+ name: t.meta.description,
42
+ value: t.key
43
+ }))
44
+ }
45
+ ]);
46
+ template = answer.template;
47
+ }
48
+ if (!template || !templates_1.templates[template]) {
49
+ throw new Error(`Unknown template: ${template}`);
50
+ }
51
+ return {
52
+ projectName,
53
+ template,
54
+ noInstall: options.install === false,
55
+ dryRun: Boolean(options.dryRun)
56
+ };
57
+ }
package/dist/copier.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.copyTemplate = copyTemplate;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ /**
9
+ * Copy template directory into target directory.
10
+ * Assumes targetDir does NOT exist.
11
+ */
12
+ async function copyTemplate(templatePath, targetDir) {
13
+ await fs_extra_1.default.copy(templatePath, targetDir);
14
+ }
package/dist/index.js ADDED
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const ora_1 = __importDefault(require("ora"));
10
+ const inquirer_1 = __importDefault(require("inquirer"));
11
+ const cli_1 = require("./cli");
12
+ const templates_1 = require("./templates");
13
+ const copier_1 = require("./copier");
14
+ const installer_1 = require("./installer");
15
+ const logger_1 = require("./logger");
16
+ const package_merger_1 = require("./package-merger");
17
+ process.on('unhandledRejection', (err) => {
18
+ if (err?.isTtyError || err?.name === 'ExitPromptError') {
19
+ logger_1.log.info('Cancelled by user');
20
+ process.exit(130);
21
+ }
22
+ });
23
+ async function run() {
24
+ const spinner = (0, ora_1.default)();
25
+ try {
26
+ const { projectName, template: templateKey, noInstall, dryRun } = await (0, cli_1.getCliContext)();
27
+ const template = templates_1.templates[templateKey];
28
+ if (!template) {
29
+ throw new Error(`Unknown template: ${templateKey}`);
30
+ }
31
+ if (!template.filesPath) {
32
+ throw new Error(`Template '${templateKey}' has no filesPath`);
33
+ }
34
+ const targetDir = path_1.default.resolve(process.cwd(), projectName);
35
+ logger_1.log.info(`Creating project: ${projectName}`);
36
+ logger_1.log.info(`Template: ${templateKey}`);
37
+ // --- Copy template (SAFE)
38
+ if (dryRun) {
39
+ if (fs_extra_1.default.existsSync(targetDir)) {
40
+ spinner.warn(`[dry-run] Directory "${projectName}" already exists`);
41
+ }
42
+ spinner.info('[dry-run] Template would be copied');
43
+ }
44
+ else {
45
+ // ⛔ overwrite decision happens ONLY here
46
+ if (fs_extra_1.default.existsSync(targetDir)) {
47
+ spinner.stop();
48
+ const { overwrite } = await inquirer_1.default.prompt([
49
+ {
50
+ type: 'confirm',
51
+ name: 'overwrite',
52
+ message: `Directory "${projectName}" already exists. Overwrite?`,
53
+ default: false
54
+ }
55
+ ]);
56
+ if (!overwrite) {
57
+ logger_1.log.info('Cancelled by user');
58
+ process.exit(0);
59
+ }
60
+ spinner.start('Cleaning target directory...');
61
+ await fs_extra_1.default.remove(targetDir);
62
+ spinner.succeed('Directory cleaned');
63
+ }
64
+ spinner.start('Copying template...');
65
+ await (0, copier_1.copyTemplate)(template.filesPath, targetDir);
66
+ spinner.succeed('Template copied');
67
+ }
68
+ // --- Merge dependencies
69
+ if (!dryRun && template.meta) {
70
+ const { dependencies, devDependencies } = template.meta;
71
+ if ((dependencies && Object.keys(dependencies).length > 0) ||
72
+ (devDependencies && Object.keys(devDependencies).length > 0)) {
73
+ spinner.start('Merging template dependencies...');
74
+ await (0, package_merger_1.mergePackageJson)(targetDir, {
75
+ dependencies,
76
+ devDependencies
77
+ });
78
+ spinner.succeed('Dependencies merged');
79
+ }
80
+ }
81
+ // --- Script cleanup (JS vs TS)
82
+ if (!dryRun && template.meta?.features?.script) {
83
+ const pkgPath = path_1.default.join(targetDir, 'package.json');
84
+ const pkg = await fs_extra_1.default.readJson(pkgPath);
85
+ if (template.meta.features.script === 'ts') {
86
+ delete pkg.devDependencies?.['@babel/core'];
87
+ delete pkg.devDependencies?.['@babel/preset-env'];
88
+ delete pkg.devDependencies?.['babel-loader'];
89
+ await fs_extra_1.default.remove(path_1.default.join(targetDir, '.babelrc'));
90
+ await fs_extra_1.default.remove(path_1.default.join(targetDir, 'babel.config.js'));
91
+ }
92
+ if (template.meta.features.script === 'js') {
93
+ delete pkg.devDependencies?.['typescript'];
94
+ delete pkg.devDependencies?.['ts-loader'];
95
+ await fs_extra_1.default.remove(path_1.default.join(targetDir, 'tsconfig.json'));
96
+ }
97
+ await fs_extra_1.default.writeJson(pkgPath, pkg, { spaces: 2 });
98
+ }
99
+ // --- Install deps
100
+ if (noInstall) {
101
+ spinner.info('Skipping install');
102
+ }
103
+ else if (dryRun) {
104
+ spinner.info('[dry-run] Would install dependencies');
105
+ }
106
+ else {
107
+ spinner.start('Installing dependencies...');
108
+ await (0, installer_1.installDeps)(targetDir);
109
+ spinner.succeed('Dependencies installed');
110
+ }
111
+ logger_1.log.success('Done!');
112
+ }
113
+ catch (err) {
114
+ spinner.stop();
115
+ console.error('❌ Error:', err?.message || err);
116
+ process.exit(1);
117
+ }
118
+ }
119
+ run().then();
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installDeps = installDeps;
4
+ const child_process_1 = require("child_process");
5
+ function installDeps(cwd) {
6
+ return new Promise((resolve, reject) => {
7
+ const child = (0, child_process_1.spawn)('npm', ['install'], {
8
+ cwd,
9
+ stdio: 'inherit',
10
+ shell: true
11
+ });
12
+ child.on('close', code => {
13
+ if (code === 0)
14
+ resolve();
15
+ else
16
+ reject(new Error('npm install failed'));
17
+ });
18
+ });
19
+ }
package/dist/logger.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.log = void 0;
7
+ const kleur_1 = __importDefault(require("kleur"));
8
+ exports.log = {
9
+ info: (msg) => console.log(kleur_1.default.cyan(msg)),
10
+ success: (msg) => console.log(kleur_1.default.green(msg)),
11
+ error: (msg) => console.error(kleur_1.default.red(msg))
12
+ };
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.mergePackageJson = mergePackageJson;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ async function mergePackageJson(targetDir, templateDeps) {
10
+ const packageJsonPath = path_1.default.join(targetDir, 'package.json');
11
+ if (!await fs_extra_1.default.pathExists(packageJsonPath)) {
12
+ throw new Error('package.json not found in generated project');
13
+ }
14
+ const pkg = await fs_extra_1.default.readJson(packageJsonPath);
15
+ pkg.dependencies = {
16
+ ...(pkg.dependencies || {}),
17
+ ...(templateDeps.dependencies || {})
18
+ };
19
+ pkg.devDependencies = {
20
+ ...(pkg.devDependencies || {}),
21
+ ...(templateDeps.devDependencies || {})
22
+ };
23
+ await fs_extra_1.default.writeJson(packageJsonPath, pkg, { spaces: 2 });
24
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadTemplates = loadTemplates;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ function loadTemplates(templatesRoot) {
10
+ const entries = fs_1.default.readdirSync(templatesRoot, { withFileTypes: true });
11
+ const result = {};
12
+ for (const entry of entries) {
13
+ if (!entry.isDirectory())
14
+ continue;
15
+ const templateDir = path_1.default.join(templatesRoot, entry.name);
16
+ const metaPath = path_1.default.join(templateDir, 'template.json');
17
+ const filesPath = path_1.default.join(templateDir, 'files');
18
+ if (!fs_1.default.existsSync(metaPath) || !fs_1.default.existsSync(filesPath))
19
+ continue;
20
+ const meta = JSON.parse(fs_1.default.readFileSync(metaPath, 'utf-8'));
21
+ result[entry.name] = {
22
+ key: entry.name,
23
+ meta,
24
+ path: templateDir,
25
+ filesPath
26
+ };
27
+ }
28
+ return result;
29
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.templates = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const template_loader_1 = require("./template-loader");
9
+ const templatesRoot = path_1.default.resolve(__dirname, '../../../packages/templates');
10
+ exports.templates = (0, template_loader_1.loadTemplates)(templatesRoot);
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "create-webpack-starter",
3
+ "version": "0.2.0",
4
+ "description": "Create a webpack starter with Pug, SCSS, TS and more",
5
+ "bin": {
6
+ "create-webpack-starter": "bin/index.js"
7
+ },
8
+ "files": [
9
+ "bin",
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "ts-node src/index.ts",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "engines": {
19
+ "node": ">=18"
20
+ },
21
+ "keywords": [
22
+ "webpack",
23
+ "starter",
24
+ "cli",
25
+ "pug",
26
+ "scss",
27
+ "less",
28
+ "javascript",
29
+ "typescript"
30
+ ],
31
+ "author": "Razerspine",
32
+ "license": "ISC",
33
+ "dependencies": {
34
+ "commander": "^12.0.0",
35
+ "fs-extra": "^11.2.0",
36
+ "inquirer": "^9.3.0",
37
+ "kleur": "^4.1.5",
38
+ "ora": "^9.1.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/fs-extra": "^11.0.4",
42
+ "@types/inquirer": "^9.0.9",
43
+ "ts-node": "^10.9.2",
44
+ "typescript": "^5.9.3"
45
+ }
46
+ }