How do you start a project? Should you build on scaffolding provided by the current technology stack or start with NPM init?

I had no choice before. I had to go to search engines. Building a project step by step based on webPack or rollup can be a lot of mistakes during development. But for now I just want to focus on the current business, pick the right scaffolding and build my project quickly so that a lot of the maintenance work can be handed over to open source authors.

Of course, well-known scaffolding tools (Vue CLI,Umi, Vite, etc.) needless to say, here I recommend a few handy tools.

  • Microbundle-crl focuses on building React components
  • TSDX focuses on building TypeScript libraries
  • CrateApp generates project packages based on the current option configuration (multiple base build tools Webpack,Parcel,Snowpack)

However, neither template library nor scaffolding will fully meet the needs of the current business, and developers will need to modify it based on the current template. For example, you need to add an open source license, change the project name, and add different dependencies to the project.

From a build perspective, there are currently two issues:

  • Lots of repetitive operations

If you build projects frequently, such as writing a business component a week. While adding open source licenses, changing project names, and adding specific dependencies is a small task every time a project is added, it can be a hassle with high frequency.

  • The underlying dependencies cannot be upgraded directly

If the developer changes the current template, then the scaffold cannot be directly upgraded when there is a destructive update (which is also rare). Although some changes will be recorded during development. But over time, developers don’t know exactly which files need to be edited or deleted to make the updated project work.

Without further notice, let’s look at how the tool Preset solves this set of problems.

Use the Preset

Start by creating a project, using Vite as an example, as shown below in package.json

{
  "name": "vite-preset"."version": "0.0.1"."author": "jump-jump"."license": "MIT"."preset": "preset.ts"."prettier": {
    "printWidth": 80."tabWidth": 2."trailingComma": "all"."singleQuote": true."arrowParens": "always"."useTabs": false."semi": true
  },
  "devDependencies": {
    "apply": "^ 0.2.15"}}Copy the code

By doing the following, we will get to the my-vue-app file.

# npm 6.x
npm init @vitejs/app my-vue-app --template vue
Copy the code

Once we have the result generated by the current command, we copy the current build file to the templates (templates/vite) folder in the root directory of vende-preset.

We then write preset command via preset. Ts (corresponding to preset”: “preset. Ts “in package.json).

import {Preset, color} from 'apply'

// The name of the project being written is displayed in the console
Preset.setName('jump-jump vite preset')

// Fetch all the files from templates/vite and carry them with. Start files such as.gitignore, etc
Preset.extract('vite')
  .withDots()


// Update the current package.json file to add dependency tailwindCSS and remove dependency sass
Preset.editNodePackages()
  .add('tailwindcss'.'^ 2.0')
  .remove('sass')

// Install all dependencies
Preset.installDependencies()

// Run prompt
Preset.instruct([
  `Run ${color.magenta('yarn dev')} to start development.`,
]).withHeading("What's next?");
Copy the code

Done!

Let’s try it out. I’ll find an appropriate folder and run the command:

// Parse the viet-preset project NPX apply C:\re-search\ viet-presetCopy the code

The previously saved vite boilerplate folder is unzipped to the current folder, and the dependencies are replaced. Of course, we can also specify a folder to install, such as

npx apply C:\re-search\vite-preset vite-demo
Copy the code

The vite template is unzipped to the vite-demo folder in the current folder.

Not only can we use the local path, of course, we can also use the Github path. Such as:

NPX apply [email protected]: useName/projectName. Git / / equivalent of NPX apply username/projectNameCopy the code

So far, it’s barely working, and there’s much more we can do than what’s shown above, so I’ll start reading the Preset commands one by one.

How to play the Preset

SetName Project name setting

As the image above shows, this command is displayed in the console when successfully set up.

Preset.setName('jump-jump preset')
Copy the code

SetTemplateDirectory Template directory Settings

This changes the extraction root path, and if not, the default option is templates.

// The file extraction root path was changed to stubs instead of templates
Preset.setTemplateDirectory('stubs');
Copy the code

Extract folder extraction

This action allows the file to be extracted from the preset boilerplate directory to the target directory. In most cases, this command solves most of the problem.

// The entire root template, templates or stubs, is currently fetched
Preset.extract();

// The templates/vite folder is currently extracted to the root directory
Preset.extract('vite'); 

// First fetch templates/presonal, then fetch the templates/presonal folder
Preset.extract('vite'); 
Preset.extract('presonal'); 

// Equivalent to Preset. Extract ('vite')
Preset.extract().from('vite'); 

// Extract to the config folder under the root path
Preset.extract().to('config');

// If the file already exists
// Note: If the request is rejected, the current progress will be aborted
Preset.extract().whenConflict('ask');

// In business, we often use this, is the current interaction mode?
// If yes, ask, otherwise overwrite
Preset.extract().whenConflict(Preset.isInteractive() ? 'ask' : 'override')


// Without this option, files starting with a. (such as.gitignore.vscode) will be ignored.
// Note: it is recommended to use the.dotfile end in the template.
// For example, gitignore.dotfile =>.gitignore
Preset.extract().withDots();
Copy the code

EditJson Edits a JSON file

Using editJson, you can overwrite and delete the contents of a JSON file.

// Edit package.json to deeply copy data
Preset.editJson('package.json')
  .merge({
    devDependencies: {
      tailwindcss: '^ 2.0'}});// Edit package.json to remove bootstrap and sas-loader from development dependencies
Preset.editJson('package.json')
  .delete([
    'devDependencies.bootstrap'.'devDependencies.sass-loader'
  ]);
Copy the code

Of course, Preset provides the simple editNodePackages control for node projects.

Preset.editNodePackages()
  // Bootstrap will be removed
  // Regardless of dependencies, devDependencies and peerDependencies
  .remove('bootstrap')
  / / add the dependencies
  .add('xxx'.'^ 2.3.0')
  / / add devDependencies
  .addDev('xxx'.'^ 2.3.0')
  / / add peerDependencies
  .addPeer('xxx'.'^ 2.3.0')
  // Set key-value pairs
  .set('license'.'MIT')
  .set('author.name'.'jump-jump')
Copy the code

InstallDependencies Installs dependencies

We need to installDependencies along with the project, which we do with installDependencies.

// Install dependency, node by default, also supports PHP
Preset.installDependencies();

// Ask the user whether to install it
Preset.installDependencies('php')
  .ifUserApproves();
Copy the code

Instruct lead

This command can be used to add a tagline to guide the user step by step, as well as a variety of colors.

import { Preset, color } from `apply`;

Preset.instruct([
  `Run ${color.magenta('yarn dev')} to start development.`,
]).withHeading("What's next?");
Copy the code

Options configuration

If developers want to add multiple templates, do they need to develop multiple projects? The answer is no, we can get the parameters through options.

npx apply C:\re-search\vite-preset vite-demo --useEsbuild
Copy the code

The current data is set to Preset. Options.

UseEsbuild is set to true by default
Preset.option('useEsbuild'.true);
// The default value of use is esbuild
Preset.option('use'.'esbuild');

// Decompress templates/esbuild if the configuration item useEsbuild is ture
// ifNotOption is inverted
Preset.extract('esbuld').ifOption('useEsbuild');

// use is strictly equal to esbuild decompress templates/esbuild
Preset.extract('esbuld').ifOptionEquals('use'.'esbuild');

Preset.extract((preset) = > {
  // Decompress templates/esbuild if the configuration item useEsbuild is ture
  if (preset.options.useEsbuild) {
    return 'esbuild';
  }

  return 'vite';
});
Copy the code

We can add configuration items before executing NPX, as shown below

mark values
--auth { auth: true }
--no-auth { auth: false }
--mode auth { mode: 'auth' }

Input Confirm Interaction Settings

The Preset setting configuration item is great. But in terms of user experience, it’s better to set it up through interaction. This way we don’t need to memorize configuration items. Enter data through human-computer interaction, and the current data is added to Preset. Prompt.

// The first argument is passed to Preset. Prompt
Preset.input('projectName'.'What is your project name? ');

// The third is an optional context string that defines the default value for the prompt.
// If the default is started in non-interactive mode, it will be used.
Preset.input('projectName'.'What is your project name? '.'jump project');

// Edit the script
Preset.editNodePackages()
	.set('name', Preset.prompt.projectName)
	.set('license'.'MIT')
	.set('author.name'.'jump-jump')

// The first argument is passed to Preset. Prompt
// The third is an optional context Boolean that defines the default value for the prompt.
// If the default is started in non-interactive mode, it will be used.
Preset.confirm('useEsLint'.'Install ESLint? '.true);
Copy the code

Delete Edit Modifies a file

Delete files in the generated folder directly using DELETE

Preset.delete('resources/sass');
Copy the code

Edit the file

// Replace the text string
Preset.edit('config/app.php').update((content) = > {
	return content.replace('en_US'.'fr_FR');
});

// Replace string {{projectName}} in readme. md file
// {{prejectName}} => prompts.name ?? 'Preset'
Preset.edit('README.md').replaceVariables(({ prompts }) = > ({
	projectName: prompts.name ?? 'Preset',}));Copy the code

Execute Run the bash command

If none of the previous commands satisfy you, you’ll have to run bash instead! Preset also provides this feature, with hooks to add various parameters.

// Use hooks to store data into context
Preset.hook(({ context, args, options }) = > {
	const allowedOptions = ['auth'.'extra'];

	context.presetName = args[2];
	context.options = Object.keys(options)
		.filter((option) = > allowedOptions.includes(option))
		.map((option) = > `--${option}`);
});

// The first argument is the name of the program or command, followed by arguments read from the context
Preset.execute('php')
	.withArguments(({ context }) = > [
		'artisan'.'ui', context.presetName, ... context.options ])// Modify the current title. The current execution will print the following string on the console instead of the default string
	.withTitle(({ context }) = > `Applying ${context.presetName}`);
Copy the code

Think further

Learning about Preset libraries, we can see that Preset has a good design style and powerful features. Instead of building a project from the ground up, Preset helps developers spawn their own tools with a few commands, and is available to record most of the changes developers make to the project.

Incremental ideas

In the process of building a template using Preset, no changes are made to the original template, making it very easy for developers to upgrade the original sample. The process of building a Preset project is actually to modify the template increment.

We should further use the idea of increments in development, where the opposite of the concept of “incremental” is “total.” Increments focus only on the impact of the difference by comparing the difference between the present and the past.

Increments have many practical implications, as we can see:

  • When the front end interacts with the back end, the front end only submits changing data
  • Rsync Incremental file synchronization
  • The web disk incrementally uploads files
  • Incremental database backup
  • Incremental code review, build, package

Chain calls

With the introduction of data-driven front-end frameworks, JQuery has been phased out (Bootstrap 5 removes JQuery). The constant upgrade of ES also helps users a lot by eliminating the need for users to build their own objects and make chain calls. But that doesn’t mean chain calls aren’t important.

Because chained calls elegantly record timing, developers can rely on the current call for analysis.

Most tools provide different configuration items. At this point we can pass in configuration items directly to use the tool.

If the current operation is sequential (the order of precedence determines the final result), it is more efficient to build objects for chain calls. Of course you could say let’s add an array configuration to determine the order. But in the face of complex order, good function naming makes it easier for users to understand the code.

And if we are faced with a complex graph structure, it will be easier to construct objects for node selection and operation. We even need to generate SQL statements based on chained calls if required.

To encourage the

If you think this article is good, I hope you can give me some encouragement and help me star under my Github blog.

Blog address

The resources

Preset

microbundle-crl

tsdx

crateApp