Element UI is one of the best UI frameworks in the world. What advantages can we learn from this excellent framework? In this article, I will share some of the tips I found useful in looking at the source code of the framework repository, preferably with the Element source code.

Tip 1: Component scaffolding

Scaffolding in the creation of new components in the application: specification code directory, reduce the workload of moving bricks, scaffolding source implementation: build/bin/new.js

 #Run the command. Parameter description    
 #Componentname componentname specifies the componentname   
 #The chineseName of the chineseName group is optional. The default value componentname is not required  
 #The node build/bin/new.js componentName [chineseName] command is described
 
 #Execute under the Element projectExample: node build/bin/new.js HelloWorldCopy the code

Scaffold treatment results:

  • 1, component style processing:

    ${componentName}.scss ${componentName}.scss

    1.2 Style entry file Packages/theme-Chalk/SRC /index. SCSS Import the shuffle style

  • 2. Component code processing:

    2.1 Generating component code files: packages/ The componentname/index. Js and packages / {the componentname} / index, js and packages/the componentname/index, js and packages / {the componentname} / SRC/ma in.vue

    2.2 Path Information of Newly added Components Import components. Json, which is a JSON object, and contains the component name and component entry path

  • 3. Generate component documents:

    3.1 generate examlpes/docs / {i18n} / component. Md, among them, i18n = [‘ en – US ‘, ‘es’,’ fr – fr ‘, ‘useful – CN]

    3.2 the title of the document of new components and the path is added to the examples/nav. Config. Json, the file is the Element of the UI components of the document directory, preserve the title of the document components and routing

  • 4. Generate unit tests:

    4.1 generate unit test files: the test/unit/specs/component. Spec. Js

  • 5. Generate component interface definitions:

    5.1 Generate component description file: types/component.d.ts

    5.2 Added interface definitions for new components in types/element-ui.d.ts

In addition to having the component code written, unit tested, documented, and, best of all, the interface defined (the compiler has friendly usage tips), a good component of an Element starts with 😄

Tip # 2: Generate code from code

Source import file generation: The Element UI currently has 80 components. To export the 80 components, the code to import, export, and declare the Vue components must be written 240 times. To reduce this effort, component imports and exports are generated based on components. Json to generate entry files.

The content of the components. Json is as follows:

The entry file has three code points (import, export, and name components) that are repeated 80 times. The following is an example of the import code statement:

Introduce a code example:

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

import Pagination from '.. /packages/pagination/index.js';
import Dialog from '.. /packages/dialog/index.js';
import Autocomplete from '.. /packages/autocomplete/index.js';
import Dropdown from '.. /packages/dropdown/index.js';
import DropdownMenu from '.. /packages/dropdown-menu/index.js';
import DropdownItem from '.. /packages/dropdown-item/index.js';
import Menu from '.. /packages/menu/index.js';
/** Omit more than 70 components import **/
import CollapseTransition from 'element-ui/src/transitions/collapse-transition';
Copy the code

To generate the above code, the main logic is: read components. Json as data, and then the template stitching, the specific implementation is as follows:


var Components = require('.. /.. /components.json');
var render = require('json-templater/string');
var uppercamelcase = require('uppercamelcase');
var endOfLine = require('os').EOL;

// Import statement syntax template
var IMPORT_TEMPLATE = 'import {{name}} from \'.. /packages/{{package}}/index.js\'; ';

var ComponentNames = Object.keys(Components);
var includeComponentTemplate = [];

ComponentNames.forEach(name= > {
  var componentName = uppercamelcase(name);
  includeComponentTemplate.push(
      // Generate a single import statement
      render(IMPORT_TEMPLATE, {
        name: componentName,
        package: name
      })
  );
});

console.info(includeComponentTemplate.join(endOfLine))

Copy the code

Implementation of the generated code: build/bin/build-entry.js

Code location: SRC /index.js

Tip # 3: Use MD to write component documentation and examples

Very elegant way to write the documents and examples: the documents and examples are written to the markdown file, and then the MD-loader is written to convert them into HTML files, then into vUE components, and then render them. This approach is very interesting in my opinion.

Take a look at the frame of the Element UI’s document page:

Routing component logic (detailed code) :

// Intercept the routing code snippet of the component document
const LOAD_DOCS_MAP = {
  'zh-CN': path= > {
    return r= > require.ensure([], () = >
      r(require(`./docs/zh-CN${path}.md`)),
    'zh-CN');
  },
  'en-US': path= > {
    return r= > require.ensure([], () = >
      r(require(`./docs/en-US${path}.md`)),
    'en-US');
  },
  'es': path= > {
    return r= > require.ensure([], () = >
      r(require(`./docs/es${path}.md`)),
    'es');
  },
  'fr-FR': path= > {
    return r= > require.ensure([], () = >
      r(require(`./docs/fr-FR${path}.md`)),
    'fr-FR'); }};Copy the code

Note that the component that the route loads is not the VUE component, but rather, a MarkDown file. This process is implemented in the WebPack packaging process by a custom loader: MarkDown to vue to achieve.

Build/mD-loader /index.js

Next, share in detail how the document achieves the effect of the component demo:

Step 1: Extend MarkDown’s Container format: Demo

:::demo ${content}:::
Copy the code

Implementation code:

const md = require('markdown-it')(); const fs = require('fs'); const path = require('path'); const mdContainer = require('markdown-it-container'); module.exports = md => { md.use(mdContainer, 'demo', { validate(params) { return params.trim().match(/^demo\s*(.*)$/); }, render(tokens, idx) { const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/); if (tokens[idx].nesting === 1) { const description = m && m.length > 1 ? m[1] : ''; const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : ''; return `<demo-block> ${description ? `<div>${md.render(description)}</div>` : ''} <! --element-demo: ${content}:element-demo--> `; } return '</demo-block>'; }}); md.use(mdContainer, 'tip'); md.use(mdContainer, 'warning'); }; const inputPath = path.resolve(__dirname, './alert.md'); const outputPath = path.resolve(__dirname, './alert.html'); const input = fs.readFileSync(inputPath, {encoding: 'utf8'}); const ounput = md.render(input); fs.writeFileSync(outputPath, ounput, {encoding: 'utf8'}); }Copy the code

Execution result:

Extract the annotation content into an instance implementation of the component

Step 2: Convert the HTML to ComponentDoc.vue

 <template>    
   <section class="content element-doc">        
    <h2>Alert warning</h2>        
    <p>Displays important information on the page.</p>        
    <h3>Custom close button</h3>        
    <p>Custom close button to text or other symbol.</p>  
    
    <! -- The example shows that this step is the most critical -->    
    <demo-block>            
        <template name="source">              
        <element-demo0 />            
        </template>            
        <template name="default"></template>            
        <slot name="highlight"></slot>        
    </demo-block>  
    
  </section>
 </template>  
Copy the code

Component:

, source location: examples/components/demo-block.vue

DemoBlockComponent looks like this:

Step 3: Demo effect

  • In the first case, the component is just a template with no other attributes, just like the description of the content slot, and passes directly through the slot.
  • Second, if the component has script content, how to handle it? The following figure

The component code is generated by calling the Vue-template-compiler module (see build/md-loader/util.js:L30)

Tip 4: Icon component example

The Element UI provides 280 ICONS. It takes a lot of overtime to move the bricks and write the documents. For aspiring programmers, of course, have an idea. Solution: Use the postCSS module to parse the style file of ICONS, extract the className of el-icon-xxx, assemble the className of all ICONS into an array, and save it to examples/icon.json

Using the style class to extract the icon name, the code is implemented as follows:

'use strict';
var postcss = require('postcss');
var fs = require('fs');
var path = require('path');
var fontFile = fs.readFileSync(path.resolve(__dirname, '.. /.. /packages/theme-chalk/src/icon.scss'), 'utf8');
// Parse CSS files with postcss
var nodes = postcss.parse(fontFile).nodes;
var classList = [];

// Get the name of icon through re
nodes.forEach((node) = > {  
    var selector = node.selector || ' ';  
    var reg = new RegExp(/\.el-icon-([^:]+):before/);  
    var arr = selector.match(reg);  
    if (arr && arr[1]) {    
    classList.push(arr[1]);  
}});
classList.reverse(); 
// Want the CSS files to be sorted in reverse order
console.info(classList.length);

fs.writeFile(
     path.resolve(__dirname, '.. /.. /examples/icon.json'), 
     JSON.stringify(classList)
 );  
Copy the code

Technique three is to generate ComponentDoc. Vue component of ICONS icon.md, unable to write code to pass in the ICONS array, it is directly injected into the prototype chain in VUE

 // Import the document
 import Vue from 'vue'
 import icon from './icon.json';
 Vue.prototype.$icon = icon;
Copy the code

Icon document writing

Icon set<ul class="icon-list"><! -- Get all icon names directly from the prototype chain --><li v-for="name in $icon" :key="name">
  {{'el-icon-' + name}}   Copy the code

Effect: element. The eleme. IO / # / useful – CN/com…

Solve so much repetitive work at once 😄

Tip 5: Document in multiple languages

Document multiple languages, using script generation for each language, a separate vUE template is generated, similar to tip 2, detailed reference: build/bin/i18n.js