Last year, had seen a moment to try ele source code, a lot of details don’t remember clearly, but its engineering construction has left a deep impression on me, the overall comprehensive clear, a line of command can do a lot of things, then I will ele slightly alters the core of the new component is applied in the actual development times, effect is not poke, simple and useful, in that case, Why don’t we share

Open element’s source code. In the project’s root directory, there is a Makefile

.PHONY: dist test default: help # build all theme build-theme: npm run build:theme install: npm install install-cn: npm install --registry=http://registry.npm.taobao.org dev: npm run dev play: npm run dev:play new: node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS)) new-lang: node build/bin/new-lang.js $(filter-out $@,$(MAKECMDGOALS)) dist: install npm run dist deploy: @npm run deploy pub: npm run pub test: npm run test:watch help: @ echo "\ [35 mmake \ [0 033 033 033 m \ [1 m command instructions \ [0 m" @ echo "033\033 [35 mmake install 033 [0 m \ \ t \ [0 033 m 033 [0 m \ \ t \ \ t 033 [0 m \ t -- -- - "@echo" \033[35mmake new <component-name> [中文名]\033[0m\t-- create a new component package. E.g. 'make new button '" @echo" \033[35mmake dev\033[0m\t\033[0m\t\033[0m\t\033[0m\t \033[0m\t\033] -- Development mode "@echo" \033[35mmake Dist \033[0m\t\033[0m\t\033[0m\t\033[0m\t \033] Generate the target file "@echo" \033[35mmake deploy\033[0m\t\033[0m\t\033[0m\t\033[0m\t \033[0m\t\033[0m\t- deploy demo" @echo "\033[35mmake Pub \033[0m\t\033[0m\t\033[0m\t\033[0m\t \033[0m\t\033[0m\t\033[0m\t\033[0m\t \033[0m\t\033[0m\t\033[0m\t\033[0m\t \033[0m\t\033[0m\t\033[0m\t\033[0m\t \033[0m\t\033] -- Add a new language to your website. For example, 'make new-lang fr'"Copy the code

Of course, Makefile itself is also very powerful. I am also ignorant of it. For the first time, πŸ˜‚ is only for make commands, which means to execute corresponding commands and run corresponding scripts. For those of you interested, take a closer look.

Today’s main use is the following command

new:
	node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS))
Copy the code

Create component.component.component.component.component.component.component.component.component.component.component.component.component.component.name

Make new <component-name> -- create new component package. For example, 'Make new button'Copy the code

“Make new button” on the command line will execute the corresponding node command “node build/bin/new.js”, which will run the script “build/bin/new.js”.

'use strict'; console.log(); process.on('exit', () => { console.log(); }); if (! Process.argv [2]) {console.error('[component name] Mandatory - Please enter new component name'); process.exit(1); } const path = require('path'); const fs = require('fs'); const fileSave = require('file-save'); const uppercamelcase = require('uppercamelcase'); const componentname = process.argv[2]; const chineseName = process.argv[3] || componentname; const ComponentName = uppercamelcase(componentname); const PackagePath = path.resolve(__dirname, '.. /.. /packages', componentname); const Files = [ { filename: 'index.js', content: `import ${ComponentName} from './src/main';  /* istanbul ignore next */ ${ComponentName}.install = function(Vue) { Vue.component(${ComponentName}.name, ${ComponentName}); }; export default ${ComponentName};` }, { filename: 'src/main.vue', content: `<template> <div class="el-${componentname}"></div> </template> <script> export default { name: 'El${ComponentName}' }; </script>` }, { filename: path.join('../../examples/docs/zh-CN', `${componentname}.md`), content: `## ${ComponentName} ${chineseName}` }, { filename: path.join('../../examples/docs/en-US', `${componentname}.md`), content: `## ${ComponentName}` }, { filename: path.join('../../examples/docs/es', `${componentname}.md`), content: `## ${ComponentName}` }, { filename: path.join('../../examples/docs/fr-FR', `${componentname}.md`), content: `## ${ComponentName}` }, { filename: path.join('../../test/unit/specs', `${componentname}.spec.js`), content: `import { createTest, destroyVM } from '../util'; import ${ComponentName} from 'packages/${componentname}';  describe('${ComponentName}', () => { let vm; afterEach(() => { destroyVM(vm); });  it('create', () => { vm = createTest(${ComponentName}, true); expect(vm.$el).to.exist; }); }); ` }, { filename: path.join('../../packages/theme-chalk/src', `${componentname}.scss`), content: `@import "mixins/mixins"; @import "common/var"; @include b(${componentname}) { }` }, { filename: path.join('../../types', `${componentname}.d.ts`), content: `import { ElementUIComponent } from './component' /** ${ComponentName} Component */ export declare class El${ComponentName} extends ElementUIComponent { }` } ]; Json const componentsFile = require('.. /.. /components.json'); If (componentsFile[ComponentName]) {console.error(' ${componentName} exists. '); process.exit(1); } componentsFile[componentname] = `./packages/${componentname}/index.js`; fileSave(path.join(__dirname, '.. /.. /components.json')) .write(JSON.stringify(componentsFile, null, ' '), 'utf8') .end('\n'); // Add to index. SCSS const sassPath = path.join(__dirname, '.. /.. /packages/theme-chalk/src/index.scss'); const sassImportText = `${fs.readFileSync(sassPath)}@import "./${componentname}.scss"; `; fileSave(sassPath) .write(sassImportText, 'utf8') .end('\n'); // Add to elementTsPath = path.join(__dirname, '.. /.. /types/element-ui.d.ts'); let elementTsText = `${fs.readFileSync(elementTsPath)} /** ${ComponentName} Component */ export class ${ComponentName} extends El${ComponentName} {}`; const index = elementTsText.indexOf('export') - 1; const importString = `import { El${ComponentName} } from './${componentname}'`; elementTsText = elementTsText.slice(0, index) + importString + '\n' + elementTsText.slice(index); fileSave(elementTsPath) .write(elementTsText, 'utf8') .end('\n'); ForEach (file => {fileSave(path.join(PackagePath, file.filename)).write(file.content, 'utf8') .end('\n'); }); // Add to nav.config.json const navConfigFile = require('.. /.. /examples/nav.config.json'); Object.keys(navConfigFile).forEach(lang => { let groups = navConfigFile[lang][4].groups; groups[groups.length - 1].list.push({ path: `/${componentname}`, title: lang === 'zh-CN' && componentname ! == chineseName ? `${ComponentName} ${chineseName}` : ComponentName }); }); fileSave(path.join(__dirname, '.. /.. /examples/nav.config.json')) .write(JSON.stringify(navConfigFile, null, ' '), 'utf8') .end('\n'); console.log('DONE! ');Copy the code

As you can see, it takes the two parameters we passed in componentName and chineseName, and then adds the component we created to component. json, defines the different templates, Filled with the componentname template and automatic file to the new packages, examples, and the test/unit/specs directory, such as a line command, help us to solve the various files, new content populated, many problems, such as standardized code, the remaining space in the template, such as single measurement in the template, We click on the new file, directly continue to edit, is not very convenient.

So the whole core idea is to use JS script to automatically create a repeatable part of the file, in the second edit.

For example, for component configuration, you can place it in components. Json. For router configuration, you can generate router.config.js from components.

Take the VUE project for example, 🌰

Install VUE scaffolding

sudo npm install -g @vue/cli

Quickly create a New View project as prompted

vue create hello-world

Run the project

npm run serve

Delete useless files

Create a Makefile at the root of your project,

.PHONY: dist test

new:
	node build/new.js $(filter-out $@,$(MAKECMDGOALS))
Copy the code

Write new. Js

'use strict'; const componentname = process.argv[2]; const chineseName = process.argv[3] || componentname; const path = require('path'); const fs = require('fs'); const fileSave = require('file-save'); const render = require('json-templater/string'); const endOfLine = require('os').EOL; const PackagePath = path.resolve(__dirname, './.. /src/views', `${componentname}.vue`); const componentsFile = require('./config/components.json'); If (componentsFile[ComponentName]) {console.error(' ${componentName} exists. '); process.exit(1); } const cleanAndWriteFile = (path, template) => { fs.truncate(path, () => { fs.writeFileSync(path, template); }); } // Add componentsFile[ComponentName] = './.. /views/${componentname}.vue` fileSave(path.join(__dirname, './config/components.json')) .write(JSON.stringify(componentsFile, null, ' '), 'utf8') .end('\n'); Config let routes = [] let routerPath = path.join(__dirname, '.. /', 'src/router/router.config.js'); let routerItem = ` { path: '/{{name}}', name: '{{name}}', component: () = > import (' {{path}})}, ` / / routerLink array let routerLinkArr = []; let routerLinkItem = `<router-link to="/{{routerName}}">{{routerName}}</router-link>` let temp Object.keys(componentsFile).forEach((key) => { routes.push(render(routerItem,{ name: key, path: componentsFile[key] })) temp = ` const routes = [${routes.join(endOfLine)}] export default routes` routerLinkArr.push(render(routerLinkItem,{ routerName: key, })) }); CleanAndWriteFile (routerPath,temp) // Add to views let viewPath = path.join(__dirname, '.. /', 'src/router/router.config.js'); let viewItem = ` <template> <div class=${componentname}> <h1>${componentname}</h1> </div> </template> ` fileSave(path.join(PackagePath)) .write(viewItem, 'utf8') .end('\n'); // Add app. vue let appPath = path.join(__dirname, '.. /', 'src/App.vue'); let AppTemp = ` <template> <div id="app"> <nav> ${routerLinkArr.join(endOfLine)} </nav> <router-view/> </div> </template> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } nav { padding: 30px; } nav a { margin-left:20px; font-weight: bold; color: #2c3e50; } nav a.router-link-exact-active { color: #42b983; } </style> ` fileSave(appPath) .write(AppTemp, 'utf8') .end('\n');Copy the code

Run the command

make new abort

make new home

make new me

View the generated directory

Okay, so the whole thing is up and running

Demo is simple, the idea is the same, there is a lot of repeated content in the project, want to automatically generate configuration files, as well as some scaffolding and so on, have the idea of automatic file generation, catch the law, let the machine to execute, after all, the machine than the human brain error probability is smaller.

If you think it’ll help, one button, three links, DDDD