create-lib-workspace 1.0.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.
Files changed (3) hide show
  1. package/README.md +118 -0
  2. package/index.js +217 -0
  3. package/package.json +22 -0
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # create-lib-workspace
2
+
3
+ A lightweight CLI tool to instantly scaffold a local development monorepo workspace for custom JavaScript libraries built with Vite.
4
+
5
+ It automatically sets up a multi-entry library with proper ESM/CJS exports and links it to a static test application using your favorite package manager—completely dependency-free.
6
+
7
+ ## Installation
8
+
9
+ You can install this tool globally to make it available anywhere on your system, or run it directly without installation.
10
+
11
+ ### 1. Global Installation (Recommended)
12
+
13
+ Install the CLI globally using your preferred package manager:
14
+
15
+ ```bash
16
+ # Using pnpm
17
+ pnpm add -g create-lib-workspace
18
+
19
+ # Using npm
20
+ npm install -g create-lib-workspace
21
+
22
+ # Using yarn
23
+ yarn global add create-lib-workspace
24
+ ```
25
+
26
+ ### 2. Run Without Installation
27
+
28
+ If you prefer not to install the package globally, you can run it on the fly using executors:
29
+
30
+ ```bash
31
+ # Using pnpm dlx
32
+ pnpm dlx create-lib-workspace
33
+
34
+ # Using npx
35
+ npx create-lib-workspace
36
+
37
+ # Using yarn dlx
38
+ yarn dlx create-lib-workspace
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ You can run the command completely empty to start the **interactive wizard**, or pre-define arguments inline.
44
+
45
+ ```bash
46
+ # Option A: Interactive Wizard (Recommended)
47
+ create-lib-workspace
48
+
49
+ # Option B: Inline Arguments
50
+ create-lib-workspace <workspace-name> <lib-name> <package-name> [pnpm|npm|yarn]
51
+ ```
52
+
53
+ ### Arguments (Optional if using Wizard)
54
+
55
+ * **`<workspace-name>`**: The name of the root directory for your project.
56
+ * **`<lib-name>`**: The directory name of the library inside the workspace.
57
+ * **`<package-name>`**: The actual package name for your `package.json` fields (e.g., `@my-scope/my-lib`).
58
+ * **`[package-manager]`**: Force a specific tool (`pnpm`, `npm`, or `yarn`). Defaults to an interactive selection if omitted.
59
+
60
+ ### Example (Inline)
61
+
62
+ ```bash
63
+ create-lib-workspace my-project core-lib @my-org/core pnpm
64
+ ```
65
+
66
+ ## ⚠️ Important Note During Setup
67
+
68
+ During execution, the script delegates project scaffolding to Vite's official creator tool.
69
+
70
+ 1. When prompted by Vite, **select `Vanilla` and `JavaScript`**.
71
+ 2. **❌ DO NOT** let Vite install dependencies or run immediately if it prompts you to do so. The script will automatically handle the clean-up, structure generation, and global symlinking right after.
72
+
73
+ ## What is generated?
74
+
75
+ The tool scaffolds a clean workspace structured as follows:
76
+
77
+ ```text
78
+ my-project/
79
+ ├── app/ # Pure static consumer app
80
+ │ ├── index.html # Test page
81
+ │ └── main.js # Imports and tests your library locally
82
+ └── core-lib/ # Your actual Library (Vite-powered)
83
+ ├── src/
84
+ │ ├── index.js # Main entry point
85
+ │ └── modifiers/ # Secondary entry point sub-module
86
+ ├── package.json # Configured with ESM/CJS exports
87
+ └── vite.config.js # Pre-configured multi-entry build setup
88
+ ```
89
+
90
+ ## Workflow / Local Development
91
+
92
+ Once the setup completes successfully, the library is automatically symlinked to the test app. You can start developing in real-time using two terminal windows:
93
+
94
+ ### Terminal 1: Library Watcher
95
+ Recompiles your library automatically on every file change. Replace `<pkg>` with your chosen package manager (`pnpm`, `npm`, or `yarn`).
96
+ ```bash
97
+ cd my-project/core-lib
98
+ <pkg> run watch
99
+ ```
100
+
101
+ ### Terminal 2: Test App Server
102
+ Serves the consumer application so you can see your library in action.
103
+ ```bash
104
+ cd my-project/app
105
+
106
+ # If you used pnpm:
107
+ pnpm dlx vite --open
108
+
109
+ # If you used npm:
110
+ npx vite --open
111
+
112
+ # If you used yarn:
113
+ yarn dlx vite --open
114
+ ```
115
+
116
+ ## License
117
+
118
+ MIT
package/index.js ADDED
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from 'child_process';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import readline from 'readline';
7
+
8
+ // Helper to create an interactive terminal prompt using built-in readline
9
+ function askQuestion(query) {
10
+ const rl = readline.createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout,
13
+ });
14
+ return new Promise((resolve) => rl.question(query, (ans) => {
15
+ rl.close();
16
+ resolve(ans.trim());
17
+ }));
18
+ }
19
+
20
+ async function main() {
21
+ console.log('\n📦 Welcome to create-lib-workspace\n');
22
+
23
+ // Parse inline arguments
24
+ const args = process.argv.slice(2);
25
+ let workspaceName = args[0];
26
+ let libName = args[1];
27
+ let packageName = args[2];
28
+ let pkgManager = args[3];
29
+
30
+ // Fallback to interactive prompts if arguments are missing
31
+ if (!workspaceName) {
32
+ workspaceName = await askQuestion('Enter the workspace directory name (e.g. my-workspace): ');
33
+ if (!workspaceName) { console.log('❌ Workspace name is required!'); process.exit(1); }
34
+ }
35
+
36
+ if (!libName) {
37
+ libName = await askQuestion('Enter the library directory name (e.g. core-lib): ');
38
+ if (!libName) { console.log('❌ Library name is required!'); process.exit(1); }
39
+ }
40
+
41
+ if (!packageName) {
42
+ packageName = await askQuestion('Enter the npm package name (e.g. @my-org/core): ');
43
+ if (!packageName) { console.log('❌ Package name is required!'); process.exit(1); }
44
+ }
45
+
46
+ if (!pkgManager) {
47
+ console.log('\nSelect package manager:\n1) pnpm (Default)\n2) npm\n3) yarn');
48
+ const choice = await askQuestion('Enter number [1-3]: ');
49
+ if (choice === '2') pkgManager = 'npm';
50
+ else if (choice === '3') pkgManager = 'yarn';
51
+ else pkgManager = 'pnpm';
52
+ }
53
+
54
+ const workspacePath = path.resolve(workspaceName);
55
+ const appPath = path.join(workspacePath, 'app');
56
+ const libPath = path.join(workspacePath, libName);
57
+
58
+ // 1. Create Workspace & App Structure
59
+ console.log('\n[1/5] Creating workspace and consumer application...');
60
+ fs.mkdirSync(appPath, { recursive: true });
61
+
62
+ const htmlContent = `<!doctype html>
63
+ <html>
64
+ <head>
65
+ <meta charset="UTF-8" />
66
+ <title>Test App</title>
67
+ </head>
68
+ <body>
69
+ <div id="app"></div>
70
+ <script type="module" src="./main.js"></script>
71
+ </body>
72
+ </html>`;
73
+
74
+ const mainJsContent = `import { pluck } from "${packageName}";
75
+ import { increaseAllOf, lowerCaseAllOf } from "${packageName}/modifiers";
76
+
77
+ const users = [
78
+ { name: 'A', age: 22 },
79
+ { name: 'B', age: 22 },
80
+ { name: 'C', age: 22 }
81
+ ];
82
+
83
+ console.log("Plucked Names:", pluck(users, 'name'));
84
+ console.log("Increased Age:", increaseAllOf(users, 'age'));
85
+ console.log("Lowercased Names:", lowerCaseAllOf(users, 'name'));`;
86
+
87
+ fs.writeFileSync(path.join(appPath, 'index.html'), htmlContent);
88
+ fs.writeFileSync(path.join(appPath, 'main.js'), mainJsContent);
89
+
90
+ // 2. Run Vite Scaffolding
91
+ console.log('\n---------------------------------------------------------');
92
+ console.log('⚠️ ATTENTION / IMPORTANT NOTE:');
93
+ console.log('Vite will now prompt you to target a framework and a variant.');
94
+ console.log('1. Please SELECT "Vanilla" and "JavaScript".');
95
+ console.log('2. ❌ DO NOT let it install dependencies or run immediately!');
96
+ console.log('---------------------------------------------------------\n');
97
+
98
+ try {
99
+ execSync(`${pkgManager} create vite ${libName} --template vanilla`, {
100
+ cwd: workspacePath,
101
+ stdio: 'inherit',
102
+ });
103
+ } catch (error) {
104
+ console.log('❌ Vite scaffolding failed or was aborted.');
105
+ process.exit(1);
106
+ }
107
+
108
+ // 3. Clean up Vite Boilerplate & Generate Library Sources
109
+ console.log('\n[2/5] Polishing library structure and writing source files...');
110
+ fs.rmSync(path.join(libPath, 'src'), { recursive: true, force: true });
111
+ fs.mkdirSync(path.join(libPath, 'src/modifiers'), { recursive: true });
112
+
113
+ // Dynamically fetch the absolute latest Vite version from registry
114
+ let viteVersion = '5.0.0';
115
+ try {
116
+ viteVersion = execSync('npm info vite version', { encoding: 'utf8' }).trim();
117
+ } catch (e) {
118
+ // Graceful fallback if no network
119
+ }
120
+
121
+ fs.writeFileSync(path.join(libPath, 'src/index.js'), `export function pluck(collection, field) {\n return collection.map(item => item[field]);\n}`);
122
+ fs.writeFileSync(path.join(libPath, 'src/modifiers/increaseAll.js'), `export function increaseAllOf(collection, field) {\n return collection.map(item => ({\n ...item,\n [field]: item[field] + 1\n }));\n}`);
123
+ fs.writeFileSync(path.join(libPath, 'src/modifiers/lowerCaseAll.js'), `export function lowerCaseAllOf(collection, field) {\n return collection.map(item => ({\n ...item,\n [field]: String(item[field]).toLowerCase()\n }));\n}`);
124
+ fs.writeFileSync(path.join(libPath, 'src/modifiers/index.js'), `import { increaseAllOf } from "./increaseAll.js";\nimport { lowerCaseAllOf } from "./lowerCaseAll.js";\n\nexport { increaseAllOf, lowerCaseAllOf };`);
125
+
126
+ // Build custom package.json
127
+ const libPackageJson = {
128
+ name: packageName,
129
+ version: '0.0.0',
130
+ type: 'module',
131
+ main: './dist/index.cjs',
132
+ module: './dist/index.js',
133
+ exports: {
134
+ '.': { import: './dist/index.js', require: './dist/index.cjs' },
135
+ './modifiers': { import: './dist/modifiers.js', require: './dist/modifiers.cjs' },
136
+ },
137
+ files: ['dist'],
138
+ scripts: {
139
+ dev: 'vite',
140
+ build: 'vite build',
141
+ watch: 'vite build --watch',
142
+ },
143
+ devDependencies: {
144
+ vite: `^${viteVersion}`,
145
+ },
146
+ };
147
+
148
+ fs.writeFileSync(path.join(libPath, 'package.json'), JSON.stringify(libPackageJson, null, 2));
149
+
150
+ // Build custom vite.config.js
151
+ const viteConfigContent = `import { defineConfig } from "vite";
152
+ import { resolve, dirname } from "path";
153
+ import { fileURLToPath } from "url";
154
+
155
+ const __dirname = dirname(fileURLToPath(import.meta.url));
156
+
157
+ export default defineConfig({
158
+ build: {
159
+ lib: {
160
+ entry: {
161
+ index: resolve(__dirname, "src/index.js"),
162
+ modifiers: resolve(__dirname, "src/modifiers/index.js")
163
+ },
164
+ name: "Lib",
165
+ formats: ["esm", "cjs"],
166
+ fileName: (format, entryName) => {
167
+ const ext = format === "esm" ? "js" : "cjs";
168
+ return \`\${entryName}.\${ext}\`;
169
+ }
170
+ }
171
+ }
172
+ });`;
173
+ fs.writeFileSync(path.join(libPath, 'vite.config.js'), viteConfigContent);
174
+
175
+ // 4. Installing and Linking Dependencies
176
+ console.log(`\n[3/5] Installing library dependencies via ${pkgManager}...`);
177
+ execSync(`${pkgManager} install`, { cwd: libPath, stdio: 'inherit' });
178
+
179
+ console.log('\n[4/5] Linking library globally and attaching to the test application...');
180
+ if (pkgManager === 'npm') {
181
+ execSync('npm link', { cwd: libPath, stdio: 'ignore' });
182
+ execSync('npm init -y', { cwd: appPath, stdio: 'ignore' });
183
+ execSync(`npm link ${packageName}`, { cwd: appPath, stdio: 'ignore' });
184
+ } else if (pkgManager === 'yarn') {
185
+ execSync('yarn link --global', { cwd: libPath, stdio: 'ignore' });
186
+ execSync('yarn init -y', { cwd: appPath, stdio: 'ignore' });
187
+ execSync(`yarn link ${packageName}`, { cwd: appPath, stdio: 'ignore' });
188
+ } else {
189
+ execSync('pnpm link --global', { cwd: libPath, stdio: 'ignore' });
190
+ execSync('pnpm init', { cwd: appPath, stdio: 'ignore' });
191
+ execSync(`pnpm link --global ${packageName}`, { cwd: appPath, stdio: 'ignore' });
192
+ }
193
+
194
+ // 5. Initial Library Build
195
+ console.log('\n[5/5] Running initial library build...');
196
+ execSync(`${pkgManager} run build`, { cwd: libPath, stdio: 'inherit' });
197
+
198
+ // Define package executor instructions
199
+ let execCmd = 'pnpm dlx';
200
+ if (pkgManager === 'npm') execCmd = 'npx';
201
+ if (pkgManager === 'yarn') execCmd = 'yarn dlx';
202
+
203
+ console.log('\n=========================================================');
204
+ console.log(' 🎉 Setup successfully completed!');
205
+ console.log('=========================================================');
206
+ console.log(' To get started, open two terminals:\n');
207
+ console.log(' Terminal 1 (Library Watcher):');
208
+ console.log(` cd ${workspaceName}/${libName} && ${pkgManager} run watch\n`);
209
+ console.log(' Terminal 2 (Test App Server):');
210
+ console.log(` cd ${workspaceName}/app && ${execCmd} vite (--open)`);
211
+ console.log('=========================================================\n');
212
+ }
213
+
214
+ main().catch((err) => {
215
+ console.error('An unexpected error occurred:', err);
216
+ process.exit(1);
217
+ });
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "create-lib-workspace",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "create-lib-workspace": "./index.js"
7
+ },
8
+ "files": [
9
+ "index.js"
10
+ ],
11
+ "license": "MIT",
12
+
13
+ "keywords": [
14
+ "cli",
15
+ "vite",
16
+ "library",
17
+ "workspace",
18
+ "scaffold"
19
+ ],
20
+ "author": "BarbWire-1 aka Barbara Kälin"
21
+
22
+ }