From the construction process of elementui source code to see the front-end UI library design

Front end forest 2020-11-13 09:54:03
construction process elementui source code



Because of business needs , In the near future, the team is going to develop its own UI Component library , The framework is still Vue. And the industry already has some mature UI The library , such as ElementUIAntDesignVant etc. .

Combining framework Vue, We choose to ElementUI On the basis of transformation . but To build the wheels It's not easy , First of all, we need to understand the whole process of building it 、 Catalog design, etc .

This paper analyzes ElementUI Complete build process , Finally, it gives some work to build a complete component library , I hope you can understand ElementUI Source code or also have build UI Component library needs you , It can help !

So let's see ElementUI The directory structure of the source code .

Directory structure analysis

  • github: Deposited Element UI Contribution Guide 、issue and PR Templates
  • build: Storage of packaging related configuration files
  • examples: Component related examples demo
  • packages: Component source
  • src: Store the entry file and some tool auxiliary functions
  • test: Unit test related documents , This is also a must for an excellent open source project
  • types: Type declaration file

Finish with the file directory , There are a few documents left ( common .babelrc.eslintc I'm not going to expand it here ), It's not common in business code :

  • .travis.yml: Continuous integration (CI) Configuration file for
  • CHANGELOG: Update log , here Element UI Offers four different languages of , It's also very intimate
  • components.json: Indicates the file path of the component , convenient webpack Get the file path of the component when packaging .
  • Developer answers to FAQs .
  • LICENSE: free use ,Element UI It uses MIT agreement
  • Makefile:Makefile Is a suitable for C/C++ Tools for , In a make Environment Directory , If there is one Makefile file . Then input make The order will be executed Makefile A target command in the file .

Before getting into the build process , So let's see ElementUI Source code of several major file directory , This is for later research ElementUI It's helpful to complete the process of .


Usually we go to see a large project from package.json The files start to look , This includes the version of the project 、 entrance 、 Script 、 Key information such as dependence .

I've got a couple of key fields here , To analyze one by one 、 Explain what he means .


Entry documents for the project

import Element from 'element-ui' It's time to introduce main Documents in

lib/element-ui.common.js yes commonjs standard , and lib/index.js yes umd standard , I will explain this in detail in the packaging module later .


Appoint npm publish Documents to be included in the contract / Catalog .


TypeScript Entrance file .


Online address of the project


When you publish a package to npm Upper time , It should also be in unpkg Get to . in other words , Your code may be in NodeJs The environment may also be Browser environment perform . For this you need to use umd Format pack ,lib/index.js yes umd standard , from webpack.conf.js Generate .


Declaration style entry file , Here is lib/theme-chalk/index.css, It will be explained in detail later .


Development 、 test 、 Production construction , pack 、 Deploy , Test cases and other related scripts .scripts Count as package.json The most important part of , I will explain the important instructions one by one .


"bootstrap": "yarn || npm i"

Installation dependency , The official recommendation is that yarn( Poking fun at a : I didn't understand at first , Thinking about bootstrap It's not the one I used before ui Library , Later I looked at , original bootstrap Which translates to Bootstrap It means , In this way, we can understand )


This instruction is mainly used to automatically generate some files .

"build:file": "node build/bin/iconInit.js & node build/bin/build-entry.js & node build/bin/i18n.js & node build/bin/version.js"

This command is long , Let's take it apart and see :


analysis icon.scss, Put all the icon The name of is in icon.json Inside At the end of the day Vue Archetype $icon On .

Finally, by traversing icon.json, Got the effect of the official website :


according to components.json file , Generate src/index.js file , The core is json-templater/string Use of plug-ins .

So let's see src/index.js file , It corresponds to the entry file of the project , There's a sentence at the top :

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

That is to say src/index.js File is made up of build/bin/build-entry.js Scripts automatically build . Let's look at the source code :

// according to components.json Generate src/index.js file
// Introduce dependencies for all components
var Components = require("../../components.json");
var fs = require("fs");
// It can make string Combine with variables Output some content
var render = require("json-templater/string");
// Turn it into a hump foo-bar >> FooBar
var uppercamelcase = require("uppercamelcase");
var path = require("path");
// os.EOL Property is a constant , Returns the line break for the current operating system (Windows System is \r\n, Other systems are \n)
var endOfLine = require("os").EOL;
// The name and path of the generated file
var OUTPUT_PATH = path.join(__dirname, "../../src/index.js");
"import {{name}} from '../packages/{{package}}/index.js';";
// var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-entry.js' */
// ...
// Get the names of all components , Store in an array
var ComponentNames = Object.keys(Components);
var includeComponentTemplate = [];
var installTemplate = [];
var listTemplate = [];
ComponentNames.forEach((name) => {
var componentName = uppercamelcase(name);
name: componentName,
package: name,
if (
].indexOf(componentName) === -1
) {
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),
// Results output to src/index.js in
fs.writeFileSync(OUTPUT_PATH, template);
console.log("[build entry] DONE:", OUTPUT_PATH);

In fact, it's just the above , according to components.json, Generate src/index.js file .


according to examples/i18n/page.json And templates , Generate... In different languages demo, The official website demo Show international processing .

ElementUI The template for the internationalization of the official website is examples/pages/template, According to different languages , Generate different files separately :
It's full of .tpl file , Each file corresponds to a template , And each tpl The documents are consistent with SFC canonical Vue file .

Let's just open a file :

export default {
data() {
return {
lang: this.$route.meta.lang,
navsData: [
path: "/design",
name: "<%= 1 >",
path: "/nav",
name: "<%= 2 >",

There are numbers in it that indicate where it needs to be internationalized .

The corresponding relationships of all internationalization related fields on the home page are stored in examples/i18n/page.json in :

Finally, what the official website shows is the page after the above internationalization processing :
Support switching different languages .

I made a circle , Back to the topic :build/bin/i18n.js What did you do for us ?

Let's think about a problem : The home page shows how to do it in different languages , Generate different vue What about the documents ?

This is it. build/bin/i18n.js What we did for us .

Take a look at the corresponding source code :

"use strict";
var fs = require("fs");
var path = require("path");
var langConfig = require("../../examples/i18n/page.json");
langConfig.forEach((lang) => {
try {
fs.statSync(path.resolve(__dirname, `../../examples/pages/${lang.lang}`));
} catch (e) {
fs.mkdirSync(path.resolve(__dirname, `../../examples/pages/${lang.lang}`));
Object.keys(lang.pages).forEach((page) => {
var templatePath = path.resolve(
var outputPath = path.resolve(
var content = fs.readFileSync(templatePath, "utf8");
var pairs = lang.pages[page];
Object.keys(pairs).forEach((key) => {
content = content.replace(
new RegExp(`<%=\\s*${key}\\s*>`, "g"),
fs.writeFileSync(outputPath, content);

The process is also very simple : Traverse examples/i18n/page.json, According to different data structures tpl The flag bit of the file , By regular matching , And replace it with the preset fields .

In this way, the internationalization of the home page of the official website is completed .


according to package.json Medium version, Generate examples/versions.json, The corresponding is the complete version list


Handle style dependent .

"build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk",

This is also associated with multiple operations , Let's take it apart and see .


This step is based on components.json, Generate package/theme-chalk/index.scss file , Import all component styles into index.scss.

In fact, it is an automatic import operation , After each new component , You don't have to manually introduce new component styles .

gulp build --gulpfile packages/theme-chalk/gulpfile.js

We all know ElementUI There are two ways to use it :

  • Introduced the global
import Vue from "vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import App from "./App.vue";
new Vue({
el: "#app",
render: (h) => h(App),
  • Introduce on demand
import Vue from "vue";
import { Pagination, Dropdown } from "element-ui";
import App from "./App.vue";
new Vue({
el: "#app",
render: (h) => h(App),

There are two ways of introduction ,Element There are two corresponding solutions when packaging .

As follows : take packages/theme-chalk All under scss The file is compiled as css, When you need a global introduction , Just introduce index.scss file ; When you introduce it on demand , Introduce the corresponding components scss File can .

There's a little bit of that , We need to think about : How to make packages/theme-chalk All under scss The file is compiled as css

In normal development , We pack 、 Work like compression is often handed over to webpack To deal with , however , In response to the above question , If we use gulp Workflow based processing will be more convenient .

gulp The relevant processing is in packages/theme-chalk/gulpfile.js in :

"use strict";
const { series, src, dest } = require("gulp");
const sass = require("gulp-sass"); // compile gulp Tools
const autoprefixer = require("gulp-autoprefixer"); // Add vendor prefix
const cssmin = require("gulp-cssmin"); // Compress css
function compile() {
return src("./src/*.scss") // src All under scss file
.pipe(sass.sync()) // hold scss File compiled into css
// Based on the target browser version , Add vendor prefix
browsers: ["ie > 9", "last 2 versions"],
cascade: false,
.pipe(cssmin()) // Compress css
.pipe(dest("./lib")); // Output to lib Next
function copyfont() {
return src("./src/fonts/**") // Read src/fonts All files under
.pipe(dest("./lib/fonts")); // Output to lib/fonts Next
} = series(compile, copyfont);

After processing , Finally, the corresponding style file will be packaged

cp-cli packages/theme-chalk/lib lib/theme-chalk
cp-cli It's a cross platform copy Tools , and CopyWebpackPlugin similar

Here is the copy file to lib/theme-chalk Next .

It's been mentioned many times components.json, Now let's get to know .


This file actually records the path of the component , In the automatic generation of files and entries will be used :

"pagination": "./packages/pagination/index.js",
"dialog": "./packages/dialog/index.js",
"autocomplete": "./packages/autocomplete/index.js",
// ...
"avatar": "./packages/avatar/index.js",
"drawer": "./packages/drawer/index.js",
"popconfirm": "./packages/popconfirm/index.js"


Store the source code and component style file of component library .

Here we use Alert The following is an example of a component :

Alert Folder

here main.vue The corresponding is the source code of components , and index.js It's the entry file :

import Alert from "./src/main";
/* istanbul ignore next */
Alert.install = function (Vue) {
Vue.component(, Alert);
export default Alert;

Import components , Then provide the component with install Method , Give Way Vue Can pass Vue.use(Alert) To use the .

About install You can see Official documents


This is where all the component related styles are stored , It has been explained above , There are index.scss( Used to export all component styles when importing globally ) Corresponding to each other scss file ( It is used to export the corresponding component style when importing on demand )


Said along while , Finally, it's all around src Folder .

above packages The folder is to process each component separately , and src The purpose of this paper is to unify all the components , Also contains custom instructions 、 The overall entrance of the project 、 Internationalization of components 、 Components mixins、 Encapsulation and public methods of animation .
Let's mainly look at the entry file , That is to say src/index.js

/* Automatically generated by './build/bin/build-entry.js' */
// Imported packages All the components under
import Pagination from "../packages/pagination/index.js";
import Dialog from "../packages/dialog/index.js";
import Autocomplete from "../packages/autocomplete/index.js";
// ...
const components = [
// ...
// Provides install Method , Help us mount some components and variables
const install = function (Vue, opts = {}) {
// Register all components to Vue above
components.forEach((component) => {
Vue.component(, component);
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) {
// Export version number 、install Method ( plug-in unit )、 And some functions such as internationalization
export default {
version: "2.13.2",
locale: locale.use,
i18n: locale.i18n,
// ...

At the beginning of the document :

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

It's actually up there scripts Of build/bin/build-entry.js We have already mentioned :src/index.js By build-entry The script is automatically generated .

This document mainly does the following things :

  • Imported packages All the components under
  • Exposed to the outside world install Method , Register all components to Vue above , And in Vue Some global variables and methods are mounted on the prototype
  • In the end install Method 、 Variable 、 Method export


Deposited ElementUI Component example of .
In fact, from the directory structure , It's not hard to see that this is a completely independent Vue project . It is mainly used for the display of official documents :
Here we mainly focus on docs Folder :
Element Official website support 4 Languages ,docs Altogether 4 A folder , The contents of each folder are basically the same .

We can see that it's all md file , And every one md file , Corresponding to the display page of the official website components respectively .

In fact, the major mainstream component library documents are now using md To write .

We have a general understanding of the source code of several major file directory , But they're scattered . Let's go from building instructions to creating new components 、 Packaging process 、 Release components and take a full look at the build process .

Construction process carding

Build instructions (Makefile)

Usually, we are used to putting the commonly used scripts of projects in package.json Medium scripts in . but ElementUI Also used. Makefile file ( Due to the large amount of content in the document , Here we have selected a few to make the following explanation ):

.PHONY: dist test
default: help
# build all theme
npm run build:theme
npm install
npm install --registry=
npm run dev
npm run dev:play
node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS))
dist: install
npm run dist
@npm run deploy
npm run pub
npm run test:watch
// Tip:
// make new <component-name> [ chinese ]
// 1、 Add a new component to components.json
// 2、 Add to index.scss
// 3、 Add to element-ui.d.ts
// 4、 establish package
// 5、 Add to nav.config.json

It's the first time I've seen , So go to Google Next , Online pair Makefile The definition is like this :

Makefile Is a suitable for C/C++ Tools for , It appeared earlier as an engineering tool in UNIX In the system , adopt make Command to perform a series of compile and join operations . In a make Environment Directory , If there is one Makefile file . Then input make The order will be executed Makefile A target command in the file .

Here I use make install As an example, it briefly describes the execution process :

  • perform make command , Find... In this directory Makefile file .
  • find Makefile File corresponding to the command line parameters install The goal is . The goal here is npm install

Build the entry file

Let's take a look at scripts Medium dev Instructions :

"npm run bootstrap &&
npm run build:file &&
cross-env NODE_ENV=development
webpack-dev-server --config build/webpack.demo.js &
node build/bin/template.js",

First npm run bootstrap Is used to install dependencies .

npm run build:file It was also mentioned earlier , It is mainly used to automatically generate some files . Mainly node build/bin/build-entry.js, Used to generate Element Entrance js: First, read the root directory components.json, This json The files are maintained Element All component path mapping relationships , The key is the component name , The value is the entry file of the source code of the component ; And then traverse the key value , Put all components into import, External exposure install Method , Put all the import The components pass through Vue.component(name, component) Method is registered as a global component , And mount some pop-up components to Vue On the prototype chain ( This is described above scripts The related scripts are explained in detail ).

After generating the entry file src/index.js And then it runs webpack-dev-server.

webpack-dev-server --config build/webpack.demo.js

This has also been mentioned before , For running Element Basic configuration of official website .

New component

We mentioned above ,Element I used makefile I wrote some extra scripts for us .

Let's focus on make new <component-name> [ chinese ] This command .

When you run this command , In fact, it runs node build/bin/new.js.

build/bin/new.js Relatively simple , The notes are also very clear , It does the following things for us :

1、 New component added to components.json

2、 stay packages/theme-chalk/src New corresponding to component scss file , To add to packages/theme-chalk/src/index.scss in

3、 Add to element-ui.d.ts, This is the corresponding type declaration file

4、 establish package( We mentioned above that the source code related to components is in package Store in the directory )

5、 Add to nav.config.json( The official website Components Menu on the left )

Packaging process analysis

ElementUI The script for package execution is :

"npm run clean &&
npm run build:file &&
npm run lint &&
webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js &&
npm run build:utils &&
npm run build:umd &&
npm run build:theme",

Now let's analyze :

npm run clean( Clean up the files )

"clean": "rimraf lib && rimraf packages/*/lib && rimraf test/**/coverage",

Package makefile before deleting .

npm run build:file( Generate entry file )

according to components.json Generate entry file src/index.js, as well as i18n Related documents . This has been analyzed above , I'm not going to explain it here .

npm run lint( Code checking )

"lint": "eslint src/**/* test/**/* packages/**/* build/**/* --quiet",

project eslint testing , This is also necessary for the current project .

File packaging related

webpack --config build/webpack.conf.js &&
webpack --config build/webpack.common.js &&
webpack --config build/webpack.component.js

Generate umd Format js file (index.js)


Generate commonjs Format js file (element-ui.common.js),require This file is loaded by default .


With components.json For entrance , Package each component into a file , For on-demand loading .

npm run build:utils( Translation tools and methods )

"build:utils": "cross-env BABEL_ENV=utils babel src --out-dir lib --ignore src/index.js",

hold src Except for index.js Documents other than the entry documents pass through babel translation , Then move to lib Under the folder .

npm run build:umd( Language pack )

"build:umd": "node build/bin/build-locale.js",

Generate umd Module language pack .

npm run build:theme( Generate style files )

"build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk",

according to components.json, Generate package/theme-chalk/index.scss. use gulp Building tools , compile scss、 Compress 、 Output css To lib Catalog .

Finally, a diagram is used to describe the whole packaging process :

Publishing process

Packing is done , It's followed by the release of the code .Element The main purpose of publishing in China is to use shell Script implementation .

Element There are three parts to the release :

1、git Release

2、npm Release

3、 Official website

The corresponding script for publishing is :

"npm run bootstrap &&
sh build/ &&
sh build/ &&
node build/bin/gen-indices.js &&
sh build/",

sh build/ Code conflict detection )

function Conduct git Conflict detection , This is mainly about testing dev Whether branches conflict , because Element Is in dev Branch to develop .

#!/usr/bin/env sh
# Switch to dev Branch
git checkout dev
# Check for uncommitted files in the local and staging areas
if test -n "$(git status --porcelain)"; then
echo 'Unclean working tree. Commit or stash changes first.' >&2;
exit 128;
# Check the local branch for errors
if ! git fetch --quiet 2>/dev/null; then
echo 'There was a problem fetching your branch. Run `git fetch` to see more...' >&2;
exit 128;
# Detect if the local branch is behind the remote branch
if test "0" != "$(git rev-list --count --left-only @'{u}'...HEAD)"; then
echo 'Remote history differ. Please pull changes.' >&2;
exit 128;
# Pass the above check , Indicates that there is no code conflict
echo 'No conflicts.' >&2;

Release npm && Official website update

dev Branch code detection does not conflict , The next step is to execute Script , Merge dev Branch to master、 Update version number 、 Push code to remote repository and publish to npm(npm publish).

The official website update is roughly : Generate static resources to examples/element-ui Under the table of contents , Then put gh-pages Branch , So that we can pass through github pages Mode of access .

Come here ElementUI The complete construction process is analyzed .

ui Component library construction points to the north

Through to ElementUI Analysis of source code file and construction process , Let's summarize the following ui What do component libraries need to do .

Directory structure

Directory structure is particularly important for large projects , A reasonable and clear structure is of great significance for later development and expansion .ui The directory structure of component library , I feel ElementUI It's very good :

|-- Element
|-- .babelrc // babel Related configuration
|-- .eslintignore
|-- .eslintrc // eslint Related configuration
|-- .gitattributes
|-- .gitignore
|-- .travis.yml // ci To configure
|-- // Version change description
|-- // common problem QA
|-- LICENSE // Copyright agreement
|-- Makefile // Script set ( Engineering compilation )
|-- // Project description document
|-- components.json // Component configuration file
|-- element_logo.svg
|-- package.json
|-- yarn.lock
|-- .github // contributor 、issue、PR Template
| |--
| |--
| |--
| |--
| |--
| |--
| |-- stale.yml
|-- build // pack
|-- examples // Sample code
|-- packages // Component source
|-- src // Entry files and various supporting documents
|-- test // Unit test file
|-- types // Type declaration 

Component development

Refer to most of UI Component library approach , Can be examples The following example code organizes and exposes an entry , Use webpack To configure a dev-server, Debugging of subsequent components 、 It's all running here dev-server Proceed under .

unit testing

UI Component as a highly abstract basic public component , It is necessary to write unit tests . Qualified unit testing is also necessary for a mature open source project .


For packaged files , Put it all together lib Under the table of contents , And remember to be in .gitignore Medium plus lib Catalog , Avoid submitting packaged results to the code base .

At the same time, according to the different ways of introduction , To provide Introduced the global (UMD) and Load on demand Two forms of bags .


The document of component library is generally accessible , So it needs to be deployed to the server , At the same time, it also needs to have the function of local preview .


After a certain version of the component library is developed , You need to publish the package to npm On . Publishing process :

  • Execute test case
  • Pack to build
  • Update version number
  • npm Package release
  • hit tag
  • Automated Deployment


After release, you need to maintain the old version before , In general, we need to pay attention to a few points :

  • issue(bug Repair )
  • pull request( Code pr)
  • Version change records )
  • Project contributors and specifications )

Reference resources

️ Three strikes of love

1. If you think this article is good , To a Share 、 give the thumbs-up 、 Looking at Three companies , Let more people see ~

2. Official account Front end forest , Regular delivery of fresh dry goods for you .

3. Special stage , Wear a mask , Personal protection .

本文为[Front end forest]所创,转载请带上原文链接,感谢

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple