如何为新Webpack项目创建类似vue-cli的菜单式配置?
Hey there! Great question—those interactive setup flows you saw in vue-cli are perfect for simplifying configurations when you’ve got a core template with lots of options. Here’s exactly how you can replicate this for your own Webpack projects:
Core Tools You’ll Need
The magic behind vue-cli’s interactive prompts comes from Inquirer.js, a popular library for creating command-line user interfaces. You’ll also want a template engine (like Handlebars) to dynamically replace values in your template files, and Node’s built-in fs module for file operations.
Step-by-Step Implementation
1. Set Up Your Template Project Structure
First, organize your files like this:
my-webpack-template/ ├── templates/ # Your base template files │ ├── package.json.hbs # Template with placeholder variables │ ├── webpack.config.js.hbs │ └── .eslintrc (optional) ├── setup.js # Your interactive setup script └── package.json
2. Install Dependencies
Run these commands to install the required packages:
npm install inquirer handlebars --save-dev
3. Write the Interactive Setup Script
Create setup.js with code like this to define your prompts and handle user input:
const inquirer = require('inquirer'); const fs = require('fs'); const handlebars = require('handlebars'); const path = require('path'); // Define your interactive questions const questions = [ { type: 'input', name: 'projectName', message: 'Project name:', default: 'my-custom-project' }, { type: 'input', name: 'projectDescription', message: 'Project description:', default: 'A custom Webpack-powered project' }, { type: 'input', name: 'author', message: 'Author:', default: `${process.env.USER} <${process.env.USER}@example.com>` }, // Add custom options for your core template { type: 'confirm', name: 'enableEslint', message: 'Enable ESLint for code linting?', default: true }, { type: 'list', name: 'cssPreprocessor', message: 'Choose a CSS preprocessor:', choices: ['Sass', 'Less', 'Stylus', 'None'], default: 'Sass' }, { type: 'checkbox', name: 'additionalFeatures', message: 'Select additional features:', choices: [ { name: 'Hot Module Replacement', value: 'hmr' }, { name: 'PWA Support', value: 'pwa' }, { name: 'Unit Testing with Jest', value: 'jest' } ] } ]; // Run the prompts and process answers inquirer.prompt(questions).then(answers => { // Create the target project directory const projectDir = path.join(process.cwd(), answers.projectName); fs.mkdirSync(projectDir, { recursive: true }); // Process and write template files const templateFiles = fs.readdirSync('./templates'); templateFiles.forEach(file => { if (file.endsWith('.hbs')) { // Compile Handlebars template const templatePath = path.join('./templates', file); const templateContent = fs.readFileSync(templatePath, 'utf8'); const compiledTemplate = handlebars.compile(templateContent); const outputContent = compiledTemplate(answers); // Remove .hbs extension for the final file const outputFileName = file.replace('.hbs', ''); const outputPath = path.join(projectDir, outputFileName); fs.writeFileSync(outputPath, outputContent); } else { // Copy non-template files (like .eslintrc) conditionally if (file === '.eslintrc' && answers.enableEslint) { const sourcePath = path.join('./templates', file); const outputPath = path.join(projectDir, file); fs.copyFileSync(sourcePath, outputPath); } } }); console.log(`✅ Project "${answers.projectName}" has been set up successfully!`); });
4. Create Template Files with Placeholders
For example, your templates/package.json.hbs would include variables that match the answer keys from your prompts:
{ "name": "{{projectName}}", "version": "1.0.0", "description": "{{projectDescription}}", "author": "{{author}}", "scripts": { "build": "webpack --mode production", "dev": "webpack serve --mode development {{#if additionalFeatures.includes('hmr')}}--hot{{/if}}" }, "devDependencies": { "webpack": "^5.0.0", "webpack-cli": "^4.0.0", {{#if enableEslint}}"eslint": "^8.0.0",{{/if}} {{#if cssPreprocessor !== 'None'"{{cssPreprocessor.toLowerCase()}}-loader": "^10.0.0",{{/if}} {{#if additionalFeatures.includes('jest')}}"jest": "^27.0.0",{{/if}} } }
5. Run the Setup Script
Add a script to your package.json to make it easy to run:
{ "scripts": { "init": "node setup.js" } }
Then users can run:
npm run init
Or if you want to make it a global CLI tool, add a bin entry to package.json and run npm link:
{ "bin": { "my-webpack-init": "./setup.js" } }
Now users can run:
my-webpack-init
Key Notes
- Question Types: Inquirer supports many types (input, confirm, list, checkbox, etc.)—mix and match to fit your options.
- Conditional Logic: Use Handlebars helpers or plain JavaScript to add conditional logic (like including ESLint only if the user opted in).
- Error Handling: Add try/catch blocks around file operations to handle cases where the project directory already exists.
内容的提问来源于stack exchange,提问作者sn4ke

