preface

I had some Element-UI for the project and had time to think about how to reduce the size and speed of the package file. To demonstrate the experiment, I used vue-CLI to generate the initial project, which was optimized only for the Element-UI theme and components.

vue init webpack vuecli
Copy the code

A complete introduction

Fully introduce UI and styles.

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Copy the code

Simply use 2 components on the page and see what happens.

<el-tabs v-model="activeName" @tab-click="handleClick">
  <el-tab-pane label="User Management" name="first">User management</el-tab-pane>
  <el-tab-pane label="Configuration Management" name="second">Configuration management</el-tab-pane>
  <el-tab-pane label="Role Management" name="third">Role management</el-tab-pane>
  <el-tab-pane label="Timed task compensation" name="fourth">Timed task compensation</el-tab-pane>
</el-tabs>

<el-steps :active="2" align-center>
  <el-step title="Step 1" description="This is a long, long, long descriptive text."></el-step>
  <el-step title="Step 2" description="This is a long, long, long descriptive text."></el-step>
  <el-step title="Step 3" description="This is a long, long, long descriptive text."></el-step>
  <el-step title="4" description="This is a long, long, long descriptive text."></el-step
></el-steps>
Copy the code

Take a look at the size of the packaged resource NPM run build –report.

Hash: 40db03677fe41f7369f6
Version: webpack 3.12. 0
Time: 20874ms
                                                  Asset       Size  Chunks                    Chunk Names
    static/css/app.cb8131545d15085cee647fe45f1d5561.css     234 kB       1  [emitted]         app
                 static/fonts/element-icons.732389d.ttf      56 kB          [emitted]
               static/js/vendor.a753ce0919c8d42e4488.js     824 kB       0  [emitted]  [big]  vendor
                  static/js/app.8c4c97edfce9c9069ea3.js    3.56 kB       1  [emitted]         app
             static/js/manifest.2ae2e69a05c33dfc65f8.js  857 bytes       2  [emitted]         manifest
                static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]
static/css/app.cb8131545d15085cee647fe45f1d5561.css.map     332 kB          [emitted]
           static/js/vendor.a753ce0919c8d42e4488.js.map    3.26 MB       0  [emitted]         vendor
              static/js/app.8c4c97edfce9c9069ea3.js.map    16.6 kB       1  [emitted]         app
         static/js/manifest.2ae2e69a05c33dfc65f8.js.map    4.97 kB       2  [emitted]         manifest
                                             index.html  506 bytes          [emitted]
Copy the code

The public module static/js/vendor.js was found to be 824KB after being packed

Take a look at the occupation of each module:

It found the largest occupation of Elcalculator ui.common.js. All module resources are 642KB in total. How can I reduce the size of the package? It’s easy to think that with the UI and style introduction, we only use three components, but the whole thing is packaged, and we can just introduce those three components here.

Introduce component styles as needed

Create a new element-variable. SCSS file.

/*icon font path variable */
$--font-path: "~element-ui/lib/theme-chalk/fonts";

/* Import as needed the SCSS files and base SCSS files of the used components */
@import "~element-ui/packages/theme-chalk/src/base.scss";
@import "~element-ui/packages/theme-chalk/src/rate.scss";
@import "~element-ui/packages/theme-chalk/src/button.scss";
@import "~element-ui/packages/theme-chalk/src/row.scss";
Copy the code

Import components as needed

Create a new element-config.js file to introduce the Element components used for the project.

import { Tabs, TabPane, Steps, Step } from 'element-ui'

export default {
  install(V) {
    V.use(Tabs)
    V.use(TabPane)
    V.use(Steps)
    V.use(Step)
  }
}
Copy the code

Package analysis after the first optimization

Add the above element-variable. SCSS and element-config.js to main.js.

import ElementUI from '@/assets/js/element-config'
import '@/assets/css/element-variables.scss'

Vue.use(ElementUI)
Copy the code

It seems that everything above is logical, the size will be reduced when packed.

Hash: 2ef987c23a5d612e00e1
Version: webpack 3.12. 0
Time: 17430ms
                                                  Asset       Size  Chunks                    Chunk Names
    static/css/app.3c70d8d75c176393318b232a345e3f0f.css    38.8 kB       1  [emitted]         app
                 static/fonts/element-icons.732389d.ttf      56 kB          [emitted]
               static/js/vendor.caa5978bb1eb0a15b097.js     824 kB       0  [emitted]  [big]  vendor
                  static/js/app.5ebb19489355acc3167b.js    3.64 kB       1  [emitted]         app
             static/js/manifest.2ae2e69a05c33dfc65f8.js  857 bytes       2  [emitted]         manifest
                static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]
static/css/app.3c70d8d75c176393318b232a345e3f0f.css.map    53.9 kB          [emitted]
           static/js/vendor.caa5978bb1eb0a15b097.js.map    3.26 MB       0  [emitted]         vendor
              static/js/app.5ebb19489355acc3167b.js.map      17 kB       1  [emitted]         app
         static/js/manifest.2ae2e69a05c33dfc65f8.js.map    4.97 kB       2  [emitted]         manifest
                                             index.html  506 bytes          [emitted]
Copy the code

Static /js/vendor.js is 824KB!

Take a look at the occupation of each module:

WHAT? Even modules are not changed, is not a basket of water, backfire.

Try packaging optimization again

Issues# 6362. Originally, it only introduced the required element-ui component, but webpack still packaged the whole UI library and style. A webPack Babel plug-in, babel-plugin-Component, is needed to truly introduce packaging on demand. This is actually written to the official document to change the configuration of the custom theme.

So NPM I babel-pugin- Componet -d after installation, in addition to the.babelrc file plug-in configuration

{
  "presets": [["env", {
      "modules": false."targets": {
        "browsers": ["1%" >."last 2 versions"."not ie <= 8"]}}],"stage-2"]."plugins": [
    "transform-vue-jsx"."transform-runtime"["component",
      {
        "libraryName": "element-ui"."styleLibraryName": "theme-chalk"}}]]Copy the code

The page is working fine and is packaged again.

Hash: f182f70cb4ceee63b5d5
Version: webpack 3.12. 0
Time: 10912ms
                                                  Asset       Size  Chunks             Chunk Names
    static/css/app.95c94c90ab11fdd4dfb413718f444d0c.css    39.9 kB       1  [emitted]  app
                 static/fonts/element-icons.732389d.ttf      56 kB          [emitted]
               static/js/vendor.befb0a8962f74af4b7e2.js     157 kB       0  [emitted]  vendor
                  static/js/app.5343843cc20a78e80469.js    3.86 kB       1  [emitted]  app
             static/js/manifest.2ae2e69a05c33dfc65f8.js  857 bytes       2  [emitted]  manifest
                static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]
static/css/app.95c94c90ab11fdd4dfb413718f444d0c.css.map    93.5 kB          [emitted]
           static/js/vendor.befb0a8962f74af4b7e2.js.map     776 kB       0  [emitted]  vendor
              static/js/app.5343843cc20a78e80469.js.map    17.1 kB       1  [emitted]  app
         static/js/manifest.2ae2e69a05c33dfc65f8.js.map    4.97 kB       2  [emitted]  manifest
                                             index.html  506 bytes          [emitted]
Copy the code

Static /js/vendor.js is indeed smaller, 157kB. Let’s look at the analysis diagram of each module.

The modules total 157.93KB, 5 times less!

Change the theme – overlay style

The element-UI theme-chalk is written using SCSS. If you use SCSS in your own project, you can change the style variable directly within the project. The new element-variable. SCSS file can therefore be overwritten with the new theme color variable.

/** * overwrites the theme color */
/* Theme color variable */
$--color-primary: #f0f;

/*icon font path variable */
$--font-path: '~element-ui/lib/theme-chalk/fonts';

/* Introducing all default styles introduces unused component styles */
// @import '~element-ui/packages/theme-chalk/src/index';

/* Import as needed the SCSS files and base SCSS files of the used components */
@import '~element-ui/packages/theme-chalk/src/base.scss';
@import '~element-ui/packages/theme-chalk/src/rate.scss';
@import '~element-ui/packages/theme-chalk/src/button.scss';
@import '~element-ui/packages/theme-chalk/src/row.scss';
Copy the code

Now our theme becomes the desired effect

As you may have noticed, it is recommended to introduce the component styles used separately, rather than all the default styles, as this would result in the introduction of unused component styles. For example, we do not use the ColorPicker component in the current case, and the component style does exist in the packaged output CSS file.

Change theme – Pure style

Through the above optimization, you can package the used components as needed, eliminate the unused components, and reduce the package size. However, there is a minor flaw: a used component style is packaged twice, once for the default style and once for the overridden style.

The problem arises because we introduce styles in two places. One is to introduce the element-UI component and its default style on demand in the.babelrc file via the babel-plugin-Component plug-in. One is to override custom styles generated by default styles in the element-variable. SCSS file.

So how do you combine the two, the babel-plugin-Component plug-in that introduces component styles on demand with user-defined styles, to achieve the goal of pure styling? Use the Element-UI theme tool for deeper theme customization.

Theme and theme tool installation

First install the theme tool, element-theme, either globally or in the project directory. It is recommended to install the clone project in the item directory, so that others can directly install dependencies and start the project.

npm i element-theme -D
Copy the code

Then install the Chalk theme, either from NPM or by pulling the latest code from GitHub.

#From the NPM
npm i element-theme-chalk -D

#out
npm i https://github.com/ElementUI/theme-chalk -D
Copy the code

Subject to build

Element-theme supports Node APIS and CLI builds.

Using the CLI

If the global installation can call the tool from the command line through et, if the installation is in the current directory, you need to access the command through node_modules/.bin/et. Execute -i (–init) to initialize the variable file. The default output is to elemental-variable. SCSS, although you can specify the file output directory by passing the parameter. If you want to enable watch mode, compile themes in real time, add the -w (–watch) parameter; If you specify a custom variable file at initialization, add the -c (–config) parameter and include your variable file name. By default, the compiled theme directory is placed under./theme. You can specify the packing directory with the -o (–out) argument.

#Initialize the variable file
et --init [file path]

#Real-time compilation
et --watch [--config variable file path] [--out theme path]

#compile
et [--config variable file path] [--out theme path] [--minimize]
Copy the code

Build through the Node API

Introduce an element-theme built through the Node API

var et = require('element-theme')

// Real-time compilation mode
et.watch({
  config: 'variables/path'.out: 'output/path'
})

/ / compile
et.run({
  config: 'variables/path'.// The configuration parameter file path defaults to './ element-variable.css '
  out: 'output/path'.// The output directory defaults to './theme '
  minimize: false.// Compress the file
  browsers: ['ie > 9'.'last 2 versions'].// Browser support
  components: ['button'.'input'] // Select the component to build a custom theme
})
Copy the code

Use the Node API to build custom themes

Here, to make theme construction more intuitive and shared by the project, use the Node API to build, and create a new theme.js file in the project root directory.

const et = require('element-theme')
// The first step is to generate the style variable file
// et.init('./src/theme.scss')
// Step 2 Modify the file as required
// ...
// The third step is to compile a custom theme style file from the variable file
et.run({
  config: './src/theme.scss'.out: './src/theme'
})
Copy the code

Add the scripts directive to package.json

{
  "scripts": {
    "theme": "node theme.js"}}Copy the code

This allows you to compile the theme with the NPM run theme directive. Compilation process:

  • Run this instruction to initialize the topic variable filetheme.scss.
  • Modify the theme styles in this file as needed.
  • Then run the command to compile the output custom theme style file put inthemeDirectory.

This completes the construction of all custom theme styles. To introduce these custom styles as needed along with the component, The babel-plugin-component parameter styleLibraryName needs to be imported as needed from the.babelrc file from the original elder-ui default style directory to the custom ~ SRC /theme directory.

"plugins": [
    "transform-vue-jsx"."transform-runtime"["component",
      {
        "libraryName": "element-ui"."styleLibraryName": "~src/theme"}]]Copy the code

When everything is ready, the project is packaged, and the CSS file is packed with only custom styles. There are no default styles and no styles that have not been introduced into the component, so we have the pure custom styles we expected!

Hash: c442bcf9d471bddfdccf
Version: webpack 3.12. 0
Time: 10174ms
                                                  Asset       Size  Chunks             Chunk Names
    static/css/app.52d411d0c1b344066ec1f456355aa7b9.css    38.8 kB       1  [emitted]  app
                static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]
               static/js/vendor.befb0a8962f74af4b7e2.js     157 kB       0  [emitted]  vendor
                  static/js/app.43c09c1f16b24d371e07.js    3.82 kB       1  [emitted]  app
             static/js/manifest.2ae2e69a05c33dfc65f8.js  857 bytes       2  [emitted]  manifest
                 static/fonts/element-icons.732389d.ttf      56 kB          [emitted]
static/css/app.52d411d0c1b344066ec1f456355aa7b9.css.map    81.3 kB          [emitted]
           static/js/vendor.befb0a8962f74af4b7e2.js.map     776 kB       0  [emitted]  vendor
              static/js/app.43c09c1f16b24d371e07.js.map    17.1 kB       1  [emitted]  app
         static/js/manifest.2ae2e69a05c33dfc65f8.js.map    4.97 kB       2  [emitted]  manifest
                                             index.html  506 bytes          [emitted]
Copy the code

Since the style is pure, the CSS file size is 38.8KB instead of 234KB, which was fully introduced, further reducing the package size.

conclusion

Based on the above experimental analysis, we can see that in order for Element-UI to achieve on-demand and pure theme style:

  • First of all bybabel-plugin-componentPlug-ins are imported on demand.
  • Then useelement-themeThe tool generates sample variable files.
  • The custom styles are then modified according to the project requirements, and all styles are generated from this file build.
  • Finally, styles will be introduced as neededstyleLibraryNamePoint to the custom styles directory.

If the style extraction requirements are not high, you can directly take the form of variable override (with the default style). Still not clear can poke here to view the case source code, give person star, hand has lingering fragrance.

End ~ PS: My opinion is limited, welcome correction.