“This is the fifth day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Written in the beginning

In this article ElementUI source code series 3 – Learn about the gen-cssfile.js file that automatically creates the component’s.scss file and generates the contents of the index. SCSS file we’ve talked about adding a new component through the following three steps:

  • Step 1 – Create the component directory structure
  • Step 2 – Create the component style file
  • Step 3 – General entry file import component

After learning from the previous two articles, we have realized the automation of the first and second steps, which can be completed by a single command (NPM run new XXX). In this chapter, we’ll automate step 3, and let’s move on to the fun part.

Preparation before class

build-entry.js

Create build-entry-js file in build/bin:

As usual, configure the command for this script file:

"scripts": {
  "dev": "webpack-dev-server --config build/webpack.common.js",
  "build": "webpack --config build/webpack.common.js",
  "build:theme": "gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk",
  "gen": "node build/bin/gen-cssfile.js",
  "new": "node build/bin/new.js",
  "build:entry": "node build/bin/build-entry.js"
},
Copy the code

Before you know it, we’ve got six commands, hopefully you’ll remember what they do, and we’ll combine them a little bit later. Don’t feel too much, this is just where, element- UI source code command is directly a whole mess, dry muddled you. (ㄒ o ㄒ)

Json – templater module

The JSON-templater module is a string template generator that helps you generate good string templates quickly and easily.

Download the package: NPM install [email protected] -d

Create test.js file in the root directory of your project.

// test.js var render = require('json-templater/string'); {{hobby. Coding}}, {{hobby. Writing}} other: {{others}} '; Var template = render(STRS, {name: 'orange ', age: 18, hobby: {coding:' write ', writing: 'write ',}, others: [' var a = 1; 'and' var b = 2 ', 'var c = 3;']. Join (' \ n ') / / an array variable string and add a newline}); console.log(template)Copy the code

Generate the main entry index.js file

Derive the index.js file string template

Before writing the build-entry-js content, let’s take a look at our existing SRC /index.js file, the main entry to the project:

import Button from '.. /packages/button/index.js'; import Divider from '.. /packages/divider/index.js'; const components = [ Button, Divider ]; const install = (Vue) => { components.forEach(component => { Vue.component(component.name, component) }) } export default { install, Button, Divider }Copy the code

To generate the file content automatically, we need to derive the string module of the file before we can generate the file content dynamically.

The first derivation is based on the contents of the JSON-templater module:

// build-entry.js var render = require('json-templater/string'); var strs = ` {{include}} const components = [ {{list}} ]; const install = function(Vue, opts = {}) { components.forEach(component => { Vue.component(component.name, component); }); }; export default { install, {{list}} }; `; var template = render(strs, { include: [ 'import Button from \'../packages/button/index.js\';'; 'import Divider from \'../packages/divider/index.js\';'; ] .join('\n'), list: ['Button', 'Divider'].join(',' + '\n'), });Copy the code

Isn’t it easy? Shouldn’t it be? Second derivation:

// build-entry.js var render = require('json-templater/string'); var uppercamelcase = require('uppercamelcase'); var strs = ` {{include}} const components = [ {{list}} ]; const install = function(Vue, opts = {}) { components.forEach(component => { Vue.component(component.name, component); }); }; export default { install, {{list}} }; `; Var ComponentNames = ['button', 'divider']; var IMPORT_TEMPLATE = 'import {{name}} from \'.. /packages/{{package}}/index.js\'; '; var includeComponentTemplate = []; var listTemplate = []; ForEach (name => {var componentName = upperCamelCase (name); // ['Button', 'Divider'] includeComponentTemplate.push(render(IMPORT_TEMPLATE, { name: componentName, package: name })); listTemplate.push(` ${componentName}`); // [' Button', ' Divider'] }) var template = render(strs, { include: includeComponentTemplate.join('\n'), list: listTemplate.join(',' + '\n'), });Copy the code

The results of the second derivation should not be difficult, we made some definitions of variables, using the form of circulation to collect the corresponding dynamic data. Now the generated template is not the final desired, then optimize it:

// build-entry.js var render = require('json-templater/string'); var uppercamelcase = require('uppercamelcase'); var endOfLine = require('os').EOL; var strs = ` {{include}} const components = [ {{list}} ]; const install = function(Vue, opts = {}) { components.forEach(component => { Vue.component(component.name, component); }); }; export default { install, {{list}} }; `; Json 'var components = require('.. /.. /components.json') var ComponentNames = Object.keys(Components); var IMPORT_TEMPLATE = 'import {{name}} from \'.. /packages/{{package}}/index.js\'; '; var includeComponentTemplate = []; var listTemplate = []; ComponentNames.forEach(name => { var componentName = uppercamelcase(name); includeComponentTemplate.push(render(IMPORT_TEMPLATE, { name: componentName, package: name })); listTemplate.push(` ${componentName}`); }) var template = render (STRS, {include: includeComponentTemplate. Join (endOfLine), / / replace a newline list: listTemplate.join(',' + endOfLine), });Copy the code

Var endOfLine = require(‘ OS ‘).eol; , replaces all newlines. Because newlines need to be compatible with different systems, the os.eol property is a constant that returns the newline of the current operating system, \r\n on Windows and \n on other systems.

Another change is the introduction of the components.json file from which the contents of the index.js file are generated.

OS module is a built-in module of Node environment. Like path, FS and other modules, OS module does not need to be downloaded separately. For more details, please click me.

Generate the contents of the index.js file

From there, we derive the final template, the contents of index.js, and then write it to a file.

// build-entry.js var render = require('json-templater/string'); var uppercamelcase = require('uppercamelcase'); var endOfLine = require('os').EOL; var strs = ` {{include}} const components = [ {{list}} ]; const install = function(Vue, opts = {}) { components.forEach(component => { Vue.component(component.name, component); }); }; export default { install, {{list}} }; `; var Components = require('.. /.. /components.json') var ComponentNames = Object.keys(Components); var IMPORT_TEMPLATE = 'import {{name}} from \'.. /packages/{{package}}/index.js\'; '; var includeComponentTemplate = []; var listTemplate = []; ComponentNames.forEach(name => { var componentName = uppercamelcase(name); includeComponentTemplate.push(render(IMPORT_TEMPLATE, { name: componentName, package: name })); listTemplate.push(` ${componentName}`); }) var template = render(strs, { include: includeComponentTemplate.join(endOfLine), list: listTemplate.join(',' + endOfLine), }); Var path = require('path'); var fs = require('fs'); var OUTPUT_PATH = path.join(__dirname, '.. /.. /src/index.js'); fs.writeFileSync(OUTPUT_PATH, template);Copy the code

NPM run build: Entry command, the contents of the index.js file will be generated automatically.

At this point, we have basically automated the component creation process in just two steps:

  • performnpm run new xxxCommand create component
  • performnpm run build:entryThe introduction of the component

We’ll be done. (✪ ✪ omega)

Build-entry-js complete source code

ElementUI’s build-entry.js file is the same as ElementUI’s build-entry.js file.

var Components = require('.. /.. /components.json'); var fs = require('fs'); var render = require('json-templater/string'); var uppercamelcase = require('uppercamelcase'); var path = require('path'); var endOfLine = require('os').EOL; var OUTPUT_PATH = path.join(__dirname, '.. /.. /src/index.js'); var IMPORT_TEMPLATE = 'import {{name}} from \'.. /packages/{{package}}/index.js\'; '; var INSTALL_COMPONENT_TEMPLATE = ' {{name}}'; var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-entry.js' */ {{include}} import locale from 'element-ui/src/locale'; import CollapseTransition from 'element-ui/src/transitions/collapse-transition'; const components = [ {{install}}, CollapseTransition ]; const install = function(Vue, opts = {}) { locale.use(opts.locale); locale.i18n(opts.i18n); components.forEach(component => { Vue.component(component.name, component); }); Vue.use(InfiniteScroll); Vue.use(Loading.directive); Vue.prototype.$ELEMENT = { size: opts.size || '', zIndex: opts.zIndex || 2000 }; Vue.prototype.$loading = Loading.service; Vue.prototype.$msgbox = MessageBox; Vue.prototype.$alert = MessageBox.alert; Vue.prototype.$confirm = MessageBox.confirm; Vue.prototype.$prompt = MessageBox.prompt; Vue.prototype.$notify = Notification; Vue.prototype.$message = Message; }; /* istanbul ignore if */ if (typeof window ! == 'undefined' && window.Vue) { install(window.Vue); } export default { version: '{{version}}', locale: locale.use, i18n: locale.i18n, install, CollapseTransition, Loading, {{list}} }; `; delete Components.font; var ComponentNames = Object.keys(Components); var includeComponentTemplate = []; var installTemplate = []; var listTemplate = []; ComponentNames.forEach(name => { var componentName = uppercamelcase(name); includeComponentTemplate.push(render(IMPORT_TEMPLATE, { name: componentName, package: name })); if (['Loading', 'MessageBox', 'Notification', 'Message', 'InfiniteScroll'].indexOf(componentName) === -1) { installTemplate.push(render(INSTALL_COMPONENT_TEMPLATE, { name: componentName, component: name })); } if (componentName ! == 'Loading') listTemplate.push(` ${componentName}`); }); var template = render(MAIN_TEMPLATE, { include: includeComponentTemplate.join(endOfLine), install: installTemplate.join(',' + endOfLine), version: process.env.VERSION || require('.. /.. /package.json').version, list: listTemplate.join(',' + endOfLine) }); fs.writeFileSync(OUTPUT_PATH, template); console.log('[build entry] DONE:', OUTPUT_PATH);Copy the code





Content of the past

  • ElementUI source code series 1 – Building project architecture from scratch, project preparation, project packaging, project testing process
  • ElementUI source code series 2 – introducing SCSS, using GULp to convert SCSS to CSS and complete and compress, using CP – CLI to move directories and files
  • ElementUI source code series 3 – Learn the gen-cssfile.js file for automatically creating component. SCSS files and generating the contents of index.scss files
  • ElementUI source code series 4 – Learn how to automatically create component directory structure and generate components. Json file contents in new.js
  • ElementUI source code series 5 – Learn the contents of the build-entry.js file that automatically generates the master entry file index.js
  • ElementUI source code series six – summary
  • ElementUI source code series 7 – Components introduced on demand




At this point, this article is finished, sa Hua Sa hua.

I hope this article has been helpful to you. If you have any questions, I am looking forward to your comments. Same old, likes + comments = you know it, favorites = you know it.