ElementUI is currently the most widely used Vue PC component library. Many Vue component libraries are based on ElementUI. As a dream front-end (salted fish), of course, you need to learn this relatively mature architecture.

Directory structure parsing

First, let’s take a look at ElementUI’s directory structure. Overall, ElementUI’s directory structure is not that different from vuE-CLI2:

  • Github: The contribution guide as well as the issue and PR templates, which are required for a mature open source project.
  • Build: No doubt, the name of the folder will tell you that it is the configuration file that holds the packaging tool.
  • Examples: Holds ElementUI component examples.
  • Packages: Stores component source code and is the main goal of source code analysis later.
  • SRC: Stores entry files and auxiliary files.
  • Test: Store unit test files. Qualified unit tests are also required for a mature open source project.
  • Types: Stores declaration files that can be imported into typescript written projectspackage.jsonTo take effect, specify the typing field whose value is the declared entry file.

With folder directories aside from the usual.babelrc,.eslintc, etc., let’s take a look at some of the strange-looking files in the root directory:

  • .travis. Yml: Continuous integration (CI) configuration file, from which scripts are executed when code is submitted, a must for mature open source projects.
  • CHANGELOG: Update log, ElementUI is prepared for 4 different language versions of the update log.
  • Components. json: configuration file, annotated with the component file path, easy to obtain the component file path when Webpack packaging.
  • Element_logo. SVG: The icon of ElementUI is in SVG format. Proper use of SVG files can greatly reduce the image size.
  • FAQ. Md: Answers to frequently asked questions by ElementUI developers.
  • LICENSE: Open source LICENSE. ElementUI uses the MIT protocol. Developers using ElementUI for secondary development are advised to note this file.
  • Makefile: As mentioned in the contribution guide under the.github folder, the first rule in the component development specification: Passmake newCreate a component directory structure that contains test code, entry files, and documentation. Among themmake newismakeOne of the commands.makeCommands are an engineering compilation tool, and makefiles define a set of rules for mutating files. Makefiles will be familiar to those who use Linux regularly.

Import file parsing

Next, let’s look at the entry file for the project. As mentioned earlier, the entry file is SRC /index.js:

/* Automatically generated by './build/bin/build-entry.js' */

import Pagination from '.. /packages/pagination/index.js';
// ...
// Import components

const components = [
  Pagination,
  Dialog,
  // ...
  // Component name
];

const install = function(Vue, opts = {}) {
  // Internationalize the configuration
  locale.use(opts.locale);
  locale.i18n(opts.i18n);

  // Batch global registry components
  components.forEach(component= > {
    Vue.component(component.name, component);
  });

  // Global register directive
  Vue.use(InfiniteScroll);
  Vue.use(Loading.directive);

  // Set the global size
  Vue.prototype.$ELEMENT = {
    size: opts.size || ' '.zIndex: opts.zIndex || 2000
  };

  // Mount methods on Vue prototypes
  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: '2.9.1'.locale: locale.use,
  i18n: locale.i18n,
  install,
  CollapseTransition,
  // Export the component
};
Copy the code

Overall, the entry file is fairly straightforward. The install function is automatically called when the vue. use method is used to invoke the plug-in. Therefore, you only need to register various instructions and components in the install function in batch and mount the global method.

ElementUI’s entry file has two important points to learn:

  1. At initialization, it provides an option to configure global properties, which greatly facilitates the use of components, as described in my previous article.
  2. Automatic generation of entry files

Automatic generation of entry files

Now let’s talk about automatic generation of entry files. Before that, how many of you noticed that the entry files are automatically generated? To my shame, I only discovered that the entry files were generated automatically when I was writing this article.

Let’s take a look at the first sentence of the entry file:

/* Automatically generated by './build/bin/build-entry.js'* /Copy the code

This file is generated by build/bin/build-entry.js, so we come to this 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;

// Output address
var OUTPUT_PATH = path.join(__dirname, '.. /.. /src/index.js');
// Import the template
var IMPORT_TEMPLATE = 'import {{name}} from \'.. /packages/{{package}}/index.js\'; ';
// Install the component template
var INSTALL_COMPONENT_TEMPLATE = ' {{name}}';
/ / template
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 = [];

// Generate template parameters in batches from the components. Json file
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}`);
});

// Pass in template parameters
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)
});

// Generate an entry file
fs.writeFileSync(OUTPUT_PATH, template);
console.log('[build entry] DONE:', OUTPUT_PATH);
Copy the code

Build-entry. js uses jSON-templater to generate an entry file. Here, we won’t focus on the jSON-templater usage, just the idea of the file.

It batches the code for importing and registering components by importing components. Json, a static file we mentioned earlier. What are the benefits of this? Instead of making multiple changes in the entry file every time a component is added or removed, with automated generation of the entry file, we only need to make one change.

Another ghost story: the previously mentioned components. Json file is also generated automatically. Due to the limited space of this article, it is up to the students to delve into it by themselves.

conclusion

Bad code varies, but good code always has the same idea that high performance is easy to maintain. As the volume of code in a project grows, in many cases, easy to maintain code is even more popular than high performance but hard to maintain code. The idea of high cohesion and low coupling is never outdated.

I have always believed that we learn source code not to blindly copy how it is written, but to learn their ideas. After all, the way code is written will soon be replaced by more and better ways to write it, but these ideas will be the most valuable asset.