Frontend Development 18 min read

Analyzing the Element‑Plus Vue3 Component Library: Architecture, TypeScript Integration, and Build Process

This article examines the Element‑Plus Vue3 component library, detailing its TypeScript refactor, Composition API usage, Teleport implementation, global‑instance API changes, internationalization support, and the multi‑tool build pipeline involving Rollup, Webpack, and Gulp.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Analyzing the Element‑Plus Vue3 Component Library: Architecture, TypeScript Integration, and Build Process

Element‑Plus is a Vue3‑based component library rebuilt with TypeScript and the Composition API. This article examines its source code, highlighting major updates such as TypeScript development, Vue 3 Composition API, Teleport, global‑instance API, internationalization, and the multi‑tool build pipeline.

TypeScript Integration

Element‑Plus adopts TypeScript, ESLint rules, a tsconfig.json , and uses Rollup plugins ( @rollup/plugin-node-resolve , rollup-plugin-terser , rollup-plugin-typescript2 , rollup-plugin-vue ) to produce ES‑module bundles. The following Rollup configuration illustrates the setup:

// build/rollup.config.bundle.js
import { nodeResolve } from "@rollup/plugin-node-resolve";
import { terser } from "rollup-plugin-terser";
import typescript from "rollup-plugin-typescript2";
const vue = require("rollup-plugin-vue");
export default [
  {
    // ... 省略前面部分内容
    plugins: [
      terser(),
      nodeResolve(),
      vue({
        target: "browser",
        css: false,
        exposeFilename: false,
      }),
      typescript({
        tsconfigOverride: {
          include: ["packages/**/*", "typings/vue-shim.d.ts"],
          exclude: ["node_modules", "packages/**/__tests__/*"],
        },
      }),
    ],
  },
];
复制代码;

Type declaration files such as typings/vue-shim.d.ts provide global types and enable import X from X.vue with proper typing.

// typings/vue-shim.d.ts
declare module '*.vue' {
  import { defineComponent } from 'vue'
  const component: ReturnType
export default component
}

declare type Nullable
= T | null;
declare type CustomizedHTMLElement
= HTMLElement & T
declare type Indexable
= {
  [key: string]: T
}
declare type Hash
= Indexable
declare type TimeoutHandle = ReturnType
declare type ComponentSize = 'large' | 'medium' | 'small' | 'mini'
复制代码;

Composition API

Vue 3’s Composition API reduces coupling and simplifies logic. The library extracts reusable hooks under packages/hooks , for example the use-attrs hook that mirrors $attrs and $listener while filtering unnecessary properties.

watchEffect(() => {
  const res = entries(instance.attrs).reduce((acm, [key, val]) => {
    if (!allExcludeKeys.includes(key) && !(excludeListeners && LISTENER_PREFIX.test(key))) {
      acm[key] = val;
    }
    return acm;
  }, {});
  attrs.value = res;
});
复制代码;

Teleport Usage

Mount‑type components such as Dialog, Drawer, Tooltip and Popover use the new Teleport feature to render their markup in a specified DOM node, controlled by the append-to-body prop.

<template>
  <teleport to="body" :disabled="!appendToBody">
    <transition name="dialog-fade" @after-enter="afterEnter" @after-leave="afterLeave">
      ...
    </transition>
  </teleport>
</template>
复制代码;

Global‑Instance API

In Vue 2 the library used global APIs ( Vue.component , Vue.use , Vue.prototype ). In Vue 3 these have been migrated to the application instance ( app ) with app.component and app.use . Message components are installed via app.use and expose global properties on app.config.globalProperties .

const install = (app: App, opt: InstallOptions): void => {
  const option = Object.assign(defaultInstallOpt, opt)
  use(option.locale)
  app.config.globalProperties.$ELEMENT = option // 全局设置默认的size属性和z-index属性
  // 全局注册所有除了plugins之外的组件
  components.forEach(component => {
    app.component(component.name, component)
  })
  plugins.forEach(plugin => {
    app.use(plugin as any)
  })
}
复制代码;
(Message as any).install = (app: App): void => {
  app.config.globalProperties.$message = Message
}
复制代码;

Internationalization

The packages/locale folder defines t and use helpers to translate strings and switch the global language, delegating date handling to dayjs instead of moment.js .

export const t = (path: string, option?): string => {
  let value;
  const array = path.split(".");
  let current = lang;
  for (let i = 0, j = array.length; i < j; i++) {
    const property = array[i];
    value = current[property];
    if (i === j - 1) return template(value, option);
    if (!value) return "";
    current = value;
  }
  return "";
};
复制代码;
export const use = (l): void => {
  lang = l || lang;
  if (lang.name) {
    dayjs.locale(lang.name);
  }
};
复制代码;

Website Packaging

The documentation site is built with Webpack, using vue-loader for .vue files, babel-loader for JS/TS, and a custom md-loader to extract <template> and <script> sections from markdown.

rules: [
  {
    test: /\.vue$/,
    use: "vue-loader",
  },
  {
    test: /\.(ts|js)x?$/,
    exclude: /node_modules/,
    loader: "babel-loader",
  },
  {
    test: /\.md$/,
    use: [
      {
        loader: "vue-loader",
        options: { compilerOptions: { preserveWhitespace: false } },
      },
      { loader: path.resolve(__dirname, "./md-loader/index.js") },
    ],
  },
  {
    test: /\.(svg|otf|ttf|woff2?|eot|gif|png|jpe?g)(\?\S*)?$/,
    loader: "url-loader",
    query: {
      limit: 10000,
      name: path.posix.join("static", "[name].[hash:7].[ext]"),
    },
  },
];
复制代码;

Component and Style Bundling

Both Rollup (ES‑module) and Webpack (UMD) are used to produce library bundles. Styles and fonts are packaged with Gulp, compiling SCSS to CSS and copying assets to lib/theme-chalk .

// packages/theme-chalk/gulpfile.js
function compile() {
  return src("./src/*.scss")
    .pipe(sass.sync())
    .pipe(autoprefixer({ cascade: false }))
    .pipe(cssmin())
    .pipe(
      rename(function (path) {
        if (!noElPrefixFile.test(path.basename)) {
          path.basename = `el-${path.basename}`;
        }
      })
    )
    .pipe(dest("./lib"));
}

function copyfont() {
  return src("./src/fonts/**").pipe(cssmin()).pipe(dest("./lib/fonts"));
}
复制代码;

Lerna Monorepo

Element‑Plus employs Lerna and Yarn workspaces to manage packages under packages/* , sharing dependencies at the root and enabling individual component publishing.

{
  "name": "@element-plus/message",
  "version": "0.0.0",
  "main": "dist/index.js",
  "license": "MIT",
  "peerDependencies": { "vue": "^3.0.0" },
  "devDependencies": { "@vue/test-utils": "^2.0.0-beta.3" }
}
复制代码;
"workspaces": ["packages/*"]
复制代码;

Conclusion

Reading the Element‑Plus source offers insight into modern component design, Vue 3 features, and multi‑tool build strategies, and contributors can submit pull requests to help the project evolve.

References

Rollup + TS library development guide – engineering setup

Quickly use Vue3’s 15 most common APIs

vue‑3‑playground repository

Vue3 official documentation – TypeScript support

Comparison of Vue3 Hooks and React Hooks

typescriptWebpackcomponent libraryLernaVue3RollupElement-Plus
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.