从0到1搭建组件库

简介 从实现项目基本架构 -> 支持多规范打包 -> 实现按需加载 -> 发布 npm 包,带你从 0 到 1 搭建组件库。
搭建项目

  • 初始化项目目录
mkdir lyn-comp-lib && cd lyn-comp-lib && npm init -y

  • 新建 packages 目录
packages 目录为组件目录,组件一个文件夹为单位,一个文件夹为一个组件
mkdir packages

  • 新建 /src/index.js
/src/index.js 作为 commonjs 规范的打包入口
mkdir src && cd src && touch index.js

  • 新建 webpack.common.js
commonjs 规范的 webpack 配置文件
touch webpack.common.js

  • 新建 webpack.umd.js
umd 规范的 webpack 配置文件
touch webpack.umd.js

  • 新建 publish.sh
负责构建项目 和 发布 npm 包
touch publish.sh

  • 安装 webpack、webpack-cli
npm i webpack webpack-cli -D

项目目录结构
从0到1搭建组件库
文章图片

开始编码 【从0到1搭建组件库】目前我们只是为了验证架构设计,所以只会写一些简单的 demo
组件
在 packages 目录中新建两个目录,作为组件目录
从0到1搭建组件库
文章图片

其实这个目录结构参考了 element-ui 组件库,为支持 按需加载 做准备
  • /packages/hello/src/index.js
// hello function export default function hello (msg) { console.log('hello ', msg) }

  • /packages/log/src/index.js
// log function export default function log (str) { console.log('log: ', str) }

引入并导出组件
在 /src/index.js 中统一引入项目中的组件并导出
// 当组件变得庞大时这部分可自动生成,element-ui 就是采用自动生成的方式 import hello from '../packages/hello/src/index' import log from '../packages/log/src/index'export default { hello, log }

编写 webpack 配置文件
  • /webpack.common.js
const path = require('path')module.exports = { entry: './src/index.js', // 使用 开发者 模式,目的是为了一会儿的调试,实际开发中可改为 production mode: 'development', output: { path: path.join(__dirname, './lib'), filename: 'lyn-comp-lib.common.js', // commonjs2 规范 libraryTarget: 'commonjs2', // 将 bundle 中的 window 对象替换为 this,不然会报 window is not defined globalObject: 'this', // 没有该配置项,组件会挂载到 default 属性下,需要 comp.default.xxx 这样使用,不方便 libraryExport: 'default' } }

  • /webpack.umd.js
const path = require('path')module.exports = { // 实际开发时这部分可以自动生成,可采用 element-ui 的方式 // 按需加载 需要将入口配置为多入口模式,一个组件 一个入口 entry: { log: './packages/log/src/index.js', hello: './packages/hello/src/index.js' }, mode: 'development', output: { path: path.join(__dirname, './lib'), filename: '[name].js', // umd 规范 libraryTarget: 'umd', globalObject: 'this', // 组件库暴露出来的 全局变量,比如 通过 script 方式引入 bundle 时就可以使用 library: 'lyn-comp-lib', libraryExport: 'default' } }

package.json
{ "name": "@liyongning/lyn-comp-lib", "version": "1.0.0", "description": "从 0 到 1 搭建组件库", "main": "lib/lyn-comp-lib.common.js", "scripts": { "build:commonjs2": "webpack --config webpack.common.js", "build:umd": "webpack --config webpack.umd.js", "build": "npm run build:commonjs2 && npm run build:umd" }, "keywords": ["组件库", "0 到 1"], "author": "Li Yong Ning", "files": [ "lib", "package.json" ], "repository": { "type": "git", "url": "https://github.com/liyongning/lyn-comp-lib.git" }, ... }

解释
  • name
    在 包 名称前加自己的 npm 账户名,采用 npm scope 的方式,包目录的组织方式和普通包不一样,而且可以有效的避免和他人的包名冲突
  • main
    告诉使用程序 ( import hello from '@liyongning/lyn-comp-lib' ) 去哪里加载组件库
  • script
    构建命令
  • files
    发布 npm 包时告诉发布程序只将 files 中指定的 文件 和 目录 上传到 npm 服务器
  • repository
    代码仓库地址,选项不强制,可以没有,不过一般都会提供,和他人共享
构建发布脚本 publish.sh
shell 脚本,负责构建组件库和发布组件库到 npm
#!/bin/bashecho '开始构建组件库'npm run buildecho '组件库构建完成,现在发布'npm publish --access public

README.md
一个项目必可少的文件,readme.md,负责告诉别人,如何使用我们的组件库
构建、发布 到这一步,不出意外,开篇定的目标就要完成了,接下来执行脚本,构建和发布组件库,当然发布之前你应该有一个自己的 npm 账户
sh publish.sh

执行脚本过程中没有报错,并最后出现以下内容,则表示发布 npm 包成功,也可以去 npm 官网 查看
... npm notice total files:5 npm notice + @liyongning/lyn-comp-lib@1.0.0

测试 接下来我们新建一个测试项目去实际使用刚才发布的组件库,去验证其是否可用以及是否达到我们的预期目标
新建项目
  • 初始化项目目录
mkdir test && cd test && npm init -y && npm i webpack webpack-cli -D && npm i @liyongning/lyn-comp-lib -S

查看 日志 或者 package.json 会发现 组件库 已经安装成功,接下来就是使用了
  • 新建 /src/index.js
import { hello } from '@liyongning/lyn-comp-lib' console.log(hello('lyn comp lib'))

  • 构建
npx webpack-cli --mode development

在 /dist 目录会生成打包后的文件 mian.js,然后在 /dist 目录新建 index.html 文件并引入 main.js,然后在浏览器打开,打开控制台,会发现输出如下内容:
从0到1搭建组件库
文章图片

  • 是否按需加载
我们在 /src/index.js 中只引入和使用了 hello 方法,在 main.js 中搜索 hello functionlog function 会发现都能搜到,说明现在是全量引入,接下来根据 使用文档(README.md) 配置按需加载
从0到1搭建组件库
文章图片

从这张图上也能看出,引入是 commonjs 的包,而不是 "./node_modules/@liyongning/lyn-comp-lib/lib/hello.js
  • 根据组件库的使用文档配置按需加载
安装 babel-plugin-component
安装 babel-loader、@babel/core
npm install --save-dev babel-loader @babel/core

// webpack.config.js const path = require('path')module.exports = { entry: './src/index.js', mode: 'development', output: { path: path.resolve(__dirname, './dist'), filename: 'main.js' }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' } ] } }

安装 @babel/preset-env
{ "presets": ["@babel/preset-env"], "plugins": [ [ "component", { "libraryName": "@liyongning/lyn-comp-lib", "style": false } ] ] }

  • 配置 package.json 的 script
{
...
scripts: {
"build": "webpack --config webpack.config.js"

}
...
}
* 执行构建命令

npm run build
* 重复上面的第 4 步,会发现打包后的文件只有 `hello function`,没有 `log function`![](https://gitee.com/liyongning/typora-image-bed/raw/master/202202071719323.jpg)而且实际的包体积也小了**OK,目标完成!!如有疑问欢迎提问,共同进步**## 链接* [组件库专栏](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzA3NTk4NjQ1OQ==&action=getalbum&album_id=2259813235891863559#wechat_redirect)- [github](https://github.com/liyongning/lyn-comp-lib.git)感谢各位的:**点赞**、**收藏**和**评论**,我们下期见。---**当学习成为了习惯,知识也就变成了常识**,扫码关注微信公众号,共同学习、进步。文章已收录到 [github](https://github.com/liyongning/blog),欢迎 Watch 和 Star。

    推荐阅读