合格前端系列第十彈-揭秘組件庫一二事(上)

摘要:因為知乎文章字數上線,本來該博文是準備分上下篇發布的,結果現在光上篇就得分上中兩篇進行發布

一、寫在前面

1、靈感來源

我平常比較喜歡對一些東西做一些記錄和總結,其中包括一些組件,積累的量比較多的時候,發現零散的堆積已經不太適合進行管理了。

於是我開始思考,有什麼好的辦法可以比較規範地來管理這些比較零散的東西呢?如果以組件庫這種形式來對組件進行管理的話,會不會更適合自己的積累並方便以後的工作呢?

於是我開始參考市場上一些優秀的 UI 組件庫,比如 element-ui、vux、 vant等,對其源碼進行拜讀,了解其架構的搭建,隨後整理出一套屬於自己的移動端 UI 組件庫

Brickies/vui?

github.com圖標

我在業餘時間活躍於各大技術社區,常有一些或工作一段時間的、或還在準備找實習工作的小夥伴問筆者一些問題:怎樣沉澱自己,做自己的框架、輪子、庫?怎樣做一個組件庫?自己做過一個組件庫會不會成為簡歷的亮點?你能不能寫一些有關組件庫開發的相關文章?…...

本著答惑解疑和分享的心情,這篇博文便誕生了。

2、最終效果圖

PC 端預覽圖

移動端預覽圖

3、問題交流

如果小夥伴在閱讀文章實戰的時候有什麼問題的話,歡迎加入討論群一起討論(群里除了一群大佬天天騷話外還有一群妹紙哦 ~ )

前端大雜燴:731175396

個人github:

xuqiang521 (qiangdada)?

github.com圖標

廢話不多說,接下來,讓我們直接進入到實戰篇吧 ~

二、環境搭建

1、搭建 NODE 環境

這裡我只談 Mac 和 window 下 NODE 的安裝

i. Mac 下的安裝

  • 如果你還沒有安裝 mac 軟體包管理器 homebrew 的話第一步得先安裝它

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

  • 使用 homebrew 安裝 node

brew install node

ii. window 下的安裝

window 環境的話直接進入 node 官網進行對應版本的下載,然後瘋狂點擊下一步即可安裝完成

安裝完成後,查看 nodenpm 版本

node -v# v9.6.1npm -v# 5.6.0

自此你電腦上 node 環境就已經搭建好了,接下來,我們需要安裝組件庫構建依賴的腳手架了。

2、構建一個 vue 項目

i. 安裝 vue-cli

# 全局安裝npm i -g vue-cli# 查看vue-cli用法vue -h# 查看版本vue -V# 2.9.3

ii. 使用 vue-cli 構建項目

使用 vue-cliinit 指令初始化一個名為 personal-components-library 的項目

# 項目基於 webpackvue init webpack personal-components-library

構建時腳手架會讓你填寫項目的一些描述和依賴,參考下面我選擇的內容進行填寫即可

# 項目名稱Project name? personal-components-library# 項目描述Project description? A Personal Vue.js components Library project# 項目作者Author? qiangdada# 項目構建 vue 版本(選擇默認項)Vue build? standalone# 是否下載 vue-router (後期會用到,這裡選 Yes)Install vue-router? Yes# 是否下載 eslint (為了制定合理的開發規範,這個必填)Use ESLint to lint your code? Yes# 安裝默認的標準 eslint 規則Pick an ESLint preset? Standard# 構建測試案例Set up unit tests? Yes# 安裝 test 依賴 (選擇 karma + mocha)Pick a test runner? karma# 構建 e2e 測試案例 (No)Setup e2e tests with Nightwatch? No# 項目初始化完是否安裝依賴 (npm)Should we run `npm install` for you after the project has been created? (recommended) npm

當你選好之後就可以等了,vue-cli 會幫你把項目搭建好,並且進行依賴安裝。

初始化項目的結構如下:

├── build webpack打包以及本地服務的文件都在裡面├── config 不同環境的配置都在這裡├── index.html 入口html├── node_modules npm安裝的依賴包都在這裡面├── package.json 項目配置信息├── README.md 項目介紹├── src 我們的源代碼│ ├── App.vue vue主入口文件│ ├── assets 資源存放(如圖片)│ ├── components 可以復用的模塊放在這裡面│ ├── main.js 入口js│ ├── router 路由管理└── webpack.config.js webpack配置文件├── static 被copy的靜態資源存放地址├── test 測試文檔和案例

如果你用 npm 下載依賴太慢或者部分資源被牆的話,建議利用 cnpm 進行依賴的下載

# 全局安裝 cnpmnpm install -g cnpm --registry=https://registry.npm.taobao.org# 使用 cnpm 進行依賴安裝cnpm i

依賴安裝完成就可以啟動你的 vue 項目啦 ~

npm run dev

然後訪問 http://localhost:8080 便可以成功訪問通過 vue-cli 構建出來的 vue 項目,至此你組件庫依賴的開發環境便已經安裝完畢。

三、構建新目錄

首先,我們要明確本節的目的,我們需要修改目錄,為了更好的開發組件庫。

我們上一節已經把搭建好了 vue 項目,但初始化出來的項目的目錄卻不能滿足一個組件庫的後續開發和維護。因此這一章節我們需要做的事情就是改造初始化出來的 vue 項目的目錄,將其變成組件庫需要的目錄,接下來就讓我們行動起來吧。

1、組件庫目錄

  1. build:這個目錄主要用來存放構建相關的文件
  2. packages: 這個目錄下主要用來存放所有組件
  3. examples:這個目錄下主要用來存放組件庫的展示 demo文檔的所有相關文件
  4. src:這個目錄主要用來管理組件的註冊的主入口,工具,mixins等(對此我們需要改造初始化出來的 src 目錄)
  5. test:這個目錄用來存放測試案例(繼續延用初始化出來的目錄)
  6. lib:組件庫打包出來後的目錄
  7. .github:作為一個開源組件庫,如果你想和別人一起開發,那麼這個目錄用來存放你自己定義的一些開發規則指導,也是非常不錯的

OK,開始改造你初始化出來的項目的目錄吧。

2、讓項目能夠重新跑起來

i. 改造 examples 目錄

從前面我們知道,我們啟動本地服務的時候,頁面的的主入口文件是 index.html 。現在我們第一步就是講頁面的主入口 htmljs 挪到 examples 目錄下面。examples 具體目錄如下

├── assets css,圖片等資源都在這├── pages 路由中所有的頁面├── src │ ├── components demo中可以復用的模塊放在這裡面│ ├── index.js 入口js│ ├── index.tpl 頁面入口│ ├── App.vue vue主入口文件│ ├── router.config.js 路由js

各個文件修改後的代碼如下

  • index.js

import Vue from vueimport App from ./Appimport router from ./router.configVue.config.productionTip = false/* eslint-disable no-new */new Vue({el: #app-container,router,components: { App },template: <App/>})

  • index.tpl

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width_=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><title>My Component Library</title></head><body><div id="app-container"> <app></app></div></body></html>

  • App.vue

<template><div id="app"> <router-view/></div></template><script>export default {name: App}</script>

  • router.config.js

import Vue from vueimport Router from vue-routerimport hello from ../pages/hello // 請自行去pages下面創建一個hello.vue,以方便之後的測試Vue.use(Router)export default new Router({routes: [ { path: /, component: hello }]})

ii. 改造 src 目錄

src 目錄主要用來存放組件的註冊的主入口文件,工具方法,mixins等文件。我們從上面 examples 的目錄可以知道,原先 src 中的一些文件是需要刪掉的,改造後的目錄如下

├── mixins mixins方法存放在這├── utils 一些常用輔助方法存放在這├── index.js 組件註冊主入口

iii. 改造 build 目錄下部分打包文件

想想小夥伴看到這,也應該知道我們現在需要做的事是什麼。沒錯,就是修改本地服務的入口文件。如果只是能夠跑起來,那麼修改 entry 中的 js 入口以及 html-webpack-plugin 的頁面入口引用即可。代碼如下(只放關鍵性代碼)

entry: { vendor: [vue, vue-router], vui: ./examples/src/index.js},// ...plugins: [ // ... // 將入口改成examples/src/index.tpl new HtmlWebpackPlugin({ chunks: [vendor, vui], template: examples/src/index.tpl, filename: index.html, inject: true })]

OK,修改好了。重新執行一次 npm run dev,然後你的項目便能在新的入口文件下跑起來

3、在本地使用組件

這一小節,我們需要實現的就是我們本地啟動的服務,能夠使用 packages 下面的組件。下面我們開發一個最簡單的 hello 組件進行講解

i. 在 packages 下創建一個 hello 組件

為了有一個良好約束性,這裡我們約束:一個組件在開始寫之前,得有一個規定的目錄及文件名進行統一管理。 packages 目錄下 hello 組件下的文件如下

├── hello │ ├── hello.vue

hello.vue 內容如下

<template> <div class="v-hello"> hello {{ message }} </div></template><script>export default { name: v-hello, props: { message: String }}</script>

ii. 在 src/index.js 對組件進行註冊

sec/index.js 文件在上面也有提及,它主要用來管理我們組件庫中所有組件的註冊

import Hello from ../packages/helloconst install = function (Vue) { if (install.installed) return Vue.component(Hello.name, Hello)}if (typeof window !== undefined && window.Vue) { install(window.Vue)}export default { install, Hello}

iii. 在 examples/src/index.js 入口 js 文件中進行引用

接下來,我需要在上節改造好的 examples 中對我們寫好的 hello 組件進行引用

import vui from src/index.js// 完整引用Vue.use(vui)// 獨立引用const { Hello } = vuiVue.component(Hello.name, Hello)

iv. 在 examples/pages/hello.vue 直接使用

examples/pages 中我們需要建立和組件名同名的 demo 文件,並對組件進行使用

<v-hello message="my component library"></v-hello>

當你運行的結果和上圖一樣的話,那麼恭喜。你又成功向組件庫的開發邁開了一步 ~

看到這裡,我需要各位讀者能夠按照自己的喜好對文件進行集中化的管理(當然,也可以參考我上面給出的 demo),只有這樣,才能夠讓我們組件庫後續的開發工作能夠順暢起來。

下一節,我們會優化 build 下面的打包文件,並帶著大家把自己的開發好的組件發布到 npm 官網,讓你的組件庫能夠被人更方便的使用!

四、改造打包文件,發布 npm 包

老規矩,章節正文開始之前,我們得清楚本章節需要做什麼以及為什麼這麼做。

  1. 由於腳手架初始的項目對於 build 文件只有一個集中打包的文件 webpack.prod.conf.js
  2. 為了之後我們的組件庫能更好的使用起來,我們需要將組件庫對應的模塊抽離全部打包到 vui.js 一個文件中(名字你喜歡啥取啥),這樣我們之後就能通過以下方式來引用我們得組件庫了

import Vue from vueimport vui from x-vuiVue.use(vui)

  1. 我們還需要將 examples 中相關的文件進行打包管理,因為我們後面還得開發組件庫的文檔官網,而文檔官網相關入口都在 examples

1、改造 build 打包文件

i. 本地服務文件的整合

我們從初始化出來項目可以看到,build 文件中的有關 webpack 的文件如下

├── webpack.base.conf.js 基礎配置文件├── webpack.dev.conf.js 本地服務配置文件├── webpack.prod.conf.js 打包配置文件├── webpack.test.conf.js 測試配置文件(這裡先不做過多描述)

初始化的打包 output 輸出的目錄是 dist ,這個目錄是整個項目打包後輸出的目錄,並不是我們組件庫需要的目錄。既然不是我們想要的,那我們想在需要的目錄是怎麼樣的呢?

  1. 組件庫主入口 js 文件 lib/vui.js(組件庫 js 主文件)
  2. 組件庫主入口 css 文件 lib/vui-css/index.css (組件庫 css 主文件,這一章節我們對 css 打包不做過多描述,後面章節會單獨講解)
  3. examples 文件打包出來的文件 examples/dist(後期文檔官網的主入口)

既然目標已經定了,接下來我們需要做的就是先整理好相關的 webpack 打包文件,如下

├── webpack.base.conf.js 基礎配置文件(配置方面和webpack.dev.conf.js的配置進行部分整合)├── webpack.dev.conf.js 本地服務配置文件(將純配置文件進行對應的刪減)├── webpack.build.js 組件庫入口文件打包配置文件(將webpack.prod.conf.js重命名)├── webpack.build.min.js examples展示文件打包配置文件(新增文件)

1、webpack.base.conf.js

開始改造 webpack.base.conf.js 文件之前我們需要先了解兩個打包文件需要做的事情

  1. webpack.build.js :輸出 lib/vui.js 組件庫 js 主文件,會用到 webpack.base.conf.jswebpack.dev.conf.js 相關配置
  2. webpack.build.min.js :輸出 examples/dist 文檔相關文件,會用到 webpack.base.conf.jswebpack.dev.conf.js 相關配置

既然兩個 webpack 打包文件都會用到 webpack.base.conf.jswebpack.dev.conf.js 相關配置,那麼我們何不將相同的一些文件都整合到 webpack.base.conf.js 文件中呢?目標明確了,接下來跟著我開搞吧

use strictconst path = require(path)const utils = require(./utils)const config = require(../config)const vueLoaderConfig = require(./vue-loader.conf)const webpack = require(webpack)const CopyWebpackPlugin = require(copy-webpack-plugin)const HtmlWebpackPlugin = require(html-webpack-plugin)function resolve (dir) { return path.join(__dirname, .., dir)}const HOST = process.env.HOSTconst PORT = process.env.PORT && Number(process.env.PORT)const createLintingRule = () => ({ test: /.(js|vue)$/, loader: eslint-loader, enforce: pre, include: [resolve(src), resolve(test)], options: { formatter: require(eslint-friendly-formatter), emitWarning: !config.dev.showEslintErrorsInOverlay }})module.exports = { context: path.resolve(__dirname, ../), // 文件入口 entry: { vendor: [vue, vue-router], vui: ./examples/src/index.js }, // 輸出目錄 output: { path: path.join(__dirname, ../examples/dist), publicPath: /, filename: [name].js }, resolve: { extensions: [.js, .vue, .json], // 此處新增了一些 alias 別名 alias: { vue$: vue/dist/vue.esm.js, @: resolve(src), src: resolve(src), packages: resolve(packages), lib: resolve(lib), components: resolve(examples/src/components) } }, // 延用原先的大部分配置 module: { rules: [ // 原先的配置... // 整合webpack.dev.conf.js中css相關配置 ...utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) ] }, // 延用原先的配置 node: { // ... }, devtool: config.dev.devtool, // 整合webpack.dev.conf.js中的devServer選項 devServer: { clientLogLevel: warning, historyApiFallback: { rewrites: [ { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, index.html) }, ], }, hot: true, contentBase: false, // since we use CopyWebpackPlugin. compress: true, host: HOST || config.dev.host, port: PORT || config.dev.port, open: config.dev.autoOpenBrowser, overlay: config.dev.errorOverlay ? { warnings: false, errors: true } : false, publicPath: config.dev.assetsPublicPath, proxy: config.dev.proxyTable, quiet: true, // necessary for FriendlyErrorsPlugin watchOptions: { poll: config.dev.poll, } }, // 整合webpack.dev.conf.js中的plugins選項 plugins: [ new webpack.DefinePlugin({ process.env: require(../config/dev.env) }), new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), new webpack.NoEmitOnErrorsPlugin(), // 頁面主入口 new HtmlWebpackPlugin({ chunks: [manifest, vendor, vui], template: examples/src/index.tpl, filename: index.html, inject: true }) ]}

2、webpack.dev.conf.js

這裡只需要將整合到 webpack.base.conf.js 中的配置刪掉即可,避免代碼重複

use strictconst utils = require(./utils)const config = require(../config)const baseWebpackConfig = require(./webpack.base.conf)const FriendlyErrorsPlugin = require(friendly-errors-webpack-plugin)const portfinder = require(portfinder)module.exports = new Promise((resolve, reject) => { portfinder.basePort = process.env.PORT || config.dev.port portfinder.getPort((err, port) => { if (err) { reject(err) } else { process.env.PORT = port baseWebpackConfig.devServer.port = port baseWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ compilationSuccessInfo: { messages: [`Your application is running here: http://${baseWebpackConfig.devServer.host}:${port}`], }, onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined })) resolve(baseWebpackConfig) } })})

webpack.base.conf.jswebpack.dev.conf.js 兩個文件都調整好後,重新執行一下 npm run dev

出現上圖表示此時你們的本地服務文件已經按照預想修改成功啦 ~

ii. 改造打包文件

1、webpack.build.js

本文件主要目的就是將組件庫中所有組件相關的文件打包到一起並輸出 lib/vui.js 主文件

use strictconst webpack = require(webpack)const config = require(./webpack.base.conf)// 修改入口文件config.entry = { vui: ./src/index.js}// 修改輸出目錄config.output = { filename: ./lib/[name].js, library: vui, libraryTarget: umd}// 配置externals選項config.externals = { vue: { root: Vue, commonjs: vue, commonjs2: vue, amd: vue }}// 配置plugins選項config.plugins = [ new webpack.DefinePlugin({ process.env: require(../config/prod.env) })]// 刪除devtool配置delete config.devtoolmodule.exports = config

2、webpack.build.min.js

該文件主要目的是為了單開一個打包地址,將 examples 中相關的文件輸出到 examples/dist 目錄(即後續文檔官網入口)

const path = require(path)const webpack = require(webpack)const merge = require(webpack-merge)const baseWebpackConfig = require(./webpack.base.conf)const config = require(../config)const ExtractTextPlugin = require(extract-text-webpack-plugin)const webpackConfig = merge(baseWebpackConfig, { output: { chunkFilename: [id].[hash].js, filename: [name].min.[hash].js }, plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false }, output: { comments: false }, sourceMap: false }), // extract css into its own file new ExtractTextPlugin({ filename: [name].[contenthash].css, allChunks: true, }), // keep module.id stable when vendor modules does not change new webpack.HashedModuleIdsPlugin(), // enable scope hoisting new webpack.optimize.ModuleConcatenationPlugin(), // split vendor js into its own file new webpack.optimize.CommonsChunkPlugin({ name: vendor, minChunks (module) { // any required modules inside node_modules are extracted to vendor return ( module.resource && /.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, ../node_modules) ) === 0 ) } }), new webpack.optimize.CommonsChunkPlugin({ name: manifest, minChunks: Infinity }), new webpack.optimize.CommonsChunkPlugin({ name: app, async: vendor-async, children: true, minChunks: 3 }), ]})module.exports = webpackConfig

當我們把這些文件都弄好的時候,最後一步就是將打包命令寫入到 package.jsonscripts 中了

"scripts": { "build:vui": "webpack --progress --hide-modules --config build/webpack.build.js && rimraf examples/dist && cross-env NODE_ENV=production webpack --progress --hide-modules --config build/webpack.build.min.js"},

執行命令,npm run build:vui,走你

至此,有關本地服務以及兩個打包文件便已改造完成,下面我們嘗試將 npm 使用起來 ~

2、發布 npm 包

注意,如果你還沒有屬於自己的 npm 賬號的話,請先自行到 npm 官網註冊一個賬號,點擊這裡進入官網進行註冊 ,註冊步驟比較簡單,這裡我就不過多做描述了,如果有疑問,可以在討論群問我

i. 先來個最簡單的 demo

mkdir qiangdada520-npm-testcd qiangdada520-npm-test# npm 包主入口js文件touch index.js# npm 包首頁介紹(具體啥內容你自行寫入即可)touch README.mdnpm init# package name: (qiangdada520-npm-test)# version: (1.0.0)# description: npm test# entry point: (index.js) index.js# test command:# git repository:# keywords: npm test# author: qiangdada# license: (ISC)

然後確定,則會生成 package.json ,如下

{ "name": "qiangdada-npm-test", "version": "1.0.0", "description": "npm test", "main": "index.js", // npm 包主入口js文件 "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "keywords": [ "npm", "test" ], "author": "qiangdada", "license": "MIT"}

接下來,我們需要在本地連接我們註冊號的 npm 賬號

npm adduser# Username: 填寫你自己的npm賬號# Password: npm賬號密碼# Email: (this IS public) 你npm賬號的認證郵箱# Logged in as xuqiang521 on https://registry.npmjs.org/. 連接成功

執行 npm publish 開始發布

npm publish# + qiangdada-npm-test@1.0.0

這個時候你再去 npm 官網就能搜索並看到你剛發布好的包啦 ~

ii. 發布組件庫

目前組件庫,我們寫了一個最簡單的 hello 組件,不過這絲毫不影響我們將其發布到 npm 官網,並且發布步驟和上面的例子一樣簡單。

修改 package.json 文件中的部分描述

// npm 包js入口文件改為 lib/vui.js"main": "lib/vui.js",// npm 發布出去的包包含的文件"files": [ "lib", "src", "packages"],// 將包的屬性改為公共可發布的"private": false,

注意,測試 npm 包發布的時候,記得每一次的 package.json 中的 version 版本要比上一次高。

開始發布

# 打包,輸出lib/vui.jsnpm run build:vui# 發布npm publish# + component-library-test@1.0.1

iii. 使用我們發布到 npm 的組件

選擇一個本地存在的 vue 項目,進入到項目

npm i component-library-test# or cnpm i component-library-test

在項目入口文件中進行組件的註冊

import Vue from vueimport vui from component-library-testVue.use(vui)

在頁面使用

<v-hello message="component library"></v-hello>

至此,我們便已經成功改造了本地服務文件,實現了組件庫主文件的打包以及文檔官網主入口的打包,並在最後學會了如何使用 npm 進行項目的發布。

下一章節,我將對組件庫中 css 文件打包進行講解。

五、css文件管理與打包

上一節,我們已經弄好了 js 文件的打包。但對於組件庫,我們要做到的不僅僅只是對 js 文件進行管理,還需要對 css 文件進行管理,這樣才能保證組件庫後續的使用。

本節中,我將會講述如何在基於 webpack 構建基礎的項目中合理使用 gulp 對 css 文件進行單獨的打包管理。

開始之前,我們需要明確兩個目標:

  1. 組件庫中組件相關的 css 文件該如何進行管理,放哪進行統一管理以及使用何種方式進行編寫
  2. css 文件將如何進行打包,單個組件如何輸出對應的單個 css

1、css 文件管理

為了方便管理,每創建一個新組件時,我們需要創建一個對應的 css 文件來管理組件的樣式,做到單一管理

i. css 目錄

這裡,我們將會把所有的 css 文件都存放到 packages/vui-css 目錄下,具體結構如下

├── src │ ├── common 存放組件公用的css文件│ ├── mixins 存放一些mixin的css文件│ ├── index.css css主入口文件│ ├── hello.css 對應hello組件的單一css文件├── gulpfile.js css打包配置文件├── package.json 相關的版本依賴

ii. css 文件編寫方式

開始寫組件的 css 前,我們要明確一些點:

  1. 當使用者引入組件庫並使用時,組件的樣式不能與使用者項目開發中樣式衝突
  2. 使用者在一些特殊情況能夠對組件樣式進行覆蓋,且能比較方便的進行修改。

符合這兩種情況的方式,個人覺得目前市場上比較好的方式就是對組件進行單一的 css 管理,並使用 bem 對 css 進行編寫。想了解 bem 的同學,點擊以下鏈接即可

  • BEM
  • 如何看待 CSS 中 BEM 的命名方式? (這是好幾年前的問題了,但仍有一定的參考性)

接下來,我們就著簡單的 hello 組件來做個講解,開始前,先放上 hello.vue 的內容

<template> <div class="v-hello"> <p class="v-hello__message">hello {{ message }}</p> </div></template><script>export default { name: v-hello, props: { message: String }}</script>

packages/vui-css/src 目錄下創建 hello.css

@b v-hello { color: #fff; transform: scale(1); @e message { background: #0067ED; }}

然後在主入口 index.css 中引入 hello.css 文件

@import ./hello.css;

examples/src/index.js 中引入組件庫樣式

import packages/vui-css/src/index.css

但從 hello.css 內容我們可以看出,這是典型的 bem 的寫法,正常是不能解析的。我們需要引入相應的 postcss 插件對 bem 語法進行解析。這裡我們將使用 餓了么團隊 開發出來的 postcss-salad 插件對 bem 語法進行解析,其次,這種 sass-like 風格的 css 文件,還需要用到一個插件叫 precss ,先安裝好依賴吧 ~

npm i postcss-salad precss -D

依賴安裝完成後,我們需要在項目根目錄下新建 salad.config.json 用來配置 bem 規則,具體規則如下

{ "browsers": ["ie > 8", "last 2 versions"], "features": { "bem": { "shortcuts": { "component": "b", "modifier": "m", "descendent": "e" }, "separators": { "descendent": "__", "modifier": "--" } } }}

接下來我們需要在項目初始化出來的 .postcssrc 文件中使用 postcss-saladprecss 插件,如下

module.exports = { "plugins": { "postcss-import": {}, "postcss-salad": require(./salad.config.json), "postcss-url": {}, "precss": {}, "autoprefixer": {}, }}

OK,這個時候再次運行項目,則能看到 css 生效,如圖

2、css 文件打包

為了將組件庫中的 css 文件進行更好的管理,更為了使用者只想引入組件庫中某一個或者幾個組件的時候也可以引入組件對應的 css 文件。因此我們需要對 css 文件進行單獨的打包,這裡我們需要用到 gulp 來進行對應的打包操作,在你開始弄打包細節前,請先確保你已經全局安裝過了 gulp ,如果沒有,請進行安裝

npm i gulp -g# 查看版本gulp -v# CLI version 3.9.1

接下來,我們看看 packages/vui-css/package.json 文件中需要用到什麼依賴

{ "name": "vui-css", "version": "1.0.0", "description": "vui css.", "main": "lib/index.css", "style": "lib/index.css", // 和組件發布一樣,也需要指定目錄 "files": [ "lib", "src" ], "scripts": { "build": "gulp build" }, "license": "MIT", "devDependencies": { "gulp": "^3.9.1", "gulp-cssmin": "^0.2.0", "gulp-postcss": "^7.0.1", "postcss-salad": "^2.0.1" }, "dependencies": {}}

我們可以看到,這裡其實和組件庫中對於 css 文件需要的依賴差不多,只不過這裡是基於 gulppostcss 插件。開始配置 gulpfile.js 前,別忘記執行 npm i 進行依賴安裝。

接下來我們開始配置 gulpfile.js,具體如下

const gulp = require(gulp)const postcss = require(gulp-postcss)const cssmin = require(gulp-cssmin)const salad = require(postcss-salad)(require(../../salad.config.json))gulp.task(compile, function () { return gulp.src(./src/*.css) // 使用postcss-salad .pipe(postcss([salad])) // 進行css壓縮 .pipe(cssmin()) // 輸出到 ./lib 目錄下 .pipe(gulp.dest(./lib))})gulp.task(build, [compile])

現在,你可以開始執行 gulp build 命令對 css 文件進行打包了。當然為了方便並更好的執行打包命令,我們現在需要在項目根目錄下的 package.json 中加上一條 css 的 build 命令,如下

"scripts": { "build:vui-css": "gulp build --gulpfile packages/vui-css/gulpfile.js && rimraf lib/vui-css && cp-cli packages/vui-css/lib lib/vui-css && rimraf packages/vui-css/lib"}

執行 npm run build:vui-css, 走你,最後打包出來的組件庫的 js 和 css 文件如下圖所示

OK,到這裡,你已經可以單獨引入組件及其樣式了。最後為了讓使用者能夠直接使用你組件的 css ,別忘記將其發布到 npm 官網哦 ~ 步驟如下

# 進到vui-css目錄cd packages/vui-css# 發布npm publish

至此,我們已經完成了 css 文件的管理和單獨打包,完成了對 css 文件單一的輸出。如此這樣,我們能夠對組件庫 css 文件的開發和管理有了一個較好的方式的同時,能夠方便組件庫的使用!

文章中所有代碼已經託管 github

xuqiang521/personal-component-library?

github.com圖標

前端交流群:731175396


推薦閱讀:

TAG:前端開發框架和庫 | Vuejs | 單元測試 |