0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何從0到1構(gòu)建基于自身業(yè)務(wù)的前端工具庫

OSC開源社區(qū) ? 來源:OSCHINA 社區(qū) ? 2023-05-17 14:59 ? 次閱讀

前言

在實(shí)際項(xiàng)目開發(fā)中無論 M 端、PC 端,或多或少都有一個(gè) utils 文件目錄去管理項(xiàng)目中用到的一些常用的工具方法,比如:時(shí)間處理、價(jià)格處理、解析 url 參數(shù)、加載腳本等,其中很多是重復(fù)、基礎(chǔ)、或基于某種業(yè)務(wù)場(chǎng)景的工具,存在項(xiàng)目間冗余的痛點(diǎn)以及工具方法規(guī)范不統(tǒng)一的問題。

在實(shí)際開發(fā)過程中,經(jīng)常使用一些開源工具庫,如 lodash,以方便、快捷的進(jìn)行項(xiàng)目開發(fā)。但是當(dāng) npm 上沒有自己中意或符合自身業(yè)務(wù)的工具時(shí),我們不得不自己動(dòng)手,此時(shí)擁有自己的、基于業(yè)務(wù)的工具庫就顯得尤為重要。

我們所熟知的 Vue、React 等諸多知名前端框架,或公司提供的一些類庫,它們是如何開發(fā)、構(gòu)建、打包出來的,本文將帶領(lǐng)你了解到如何從 0 到 1 構(gòu)建基于自身業(yè)務(wù)的前端工具庫。

構(gòu)建工具庫主流方案

1. WEBPACK

webpack 提供了構(gòu)建和打包不同模塊化規(guī)則的庫,只是需要自己去搭建開發(fā)底層架構(gòu)。

vue-cli,基于 webpack , vue-cli 腳手架工具可以快速初始化一個(gè) vue 應(yīng)用,它也可以初始化一個(gè)構(gòu)建庫。

2. ROLLUP

rollup 是一個(gè)專門針對(duì) JavaScript 模塊打包器,可以將應(yīng)用或庫的小塊代碼編譯成更復(fù)雜的功能代碼。

Vue、React 等許多流行前端框架的構(gòu)建和打包都能看到 rollup 的身影。

為什么采用 ROLLUP 而不是 WEBPACK

webpack 主要職能是開發(fā)應(yīng)用,而 rollup 主要針對(duì)的就是 js 庫的開發(fā),如果你要開發(fā) js 庫,那 webpack 的繁瑣配置和打包后的文件體積就不太適用了,通過 webpack 打包構(gòu)建出來的源代碼增加了很多工具函數(shù)以外的模塊依賴代碼。

rollup 只是把業(yè)務(wù)代碼轉(zhuǎn)碼成目標(biāo) js ,小巧且輕便。rollup 對(duì)于代碼的 Tree-shaking 和 ES6 模塊有著算法優(yōu)勢(shì)上的支持,如果只想構(gòu)建一個(gè)簡單的庫,并且是基于 ES6 開發(fā)的,加上其簡潔的 API,rollup 得到更多開發(fā)者的青睞。

工具庫底層架構(gòu)設(shè)計(jì)

構(gòu)建工具庫底層架構(gòu)大概需要哪些功能的支持:? c39d8f0a-f41c-11ed-90ce-dac502259ad0.png

架構(gòu)依賴需知

在對(duì)底層架構(gòu)設(shè)計(jì)的基礎(chǔ)上,首先需要把用到的依賴庫簡單熟悉一下:

rollup 全家桶

?? rollup(工具庫打包構(gòu)建核心包) ?? rollup-plugin-livereload(rollup 插件,熱更新,方便本地 debugger 開發(fā)) ?? rollup-plugin-serve(rollup 插件,本地服務(wù)代理,方便在本地 html 中調(diào)試工具) ?? rollup-plugin-terser(rollup 插件,代碼壓縮混淆) ?? rollup-plugin-visualizer(rollup 插件,可視化并分析 Rollup bundle,以查看模塊占用) ?? @rollup/plugin-babel(rollup 插件,rollup 的 babel 插件,ES6 轉(zhuǎn) ES5) ?? @rollup/plugin-commonjs(rollup 插件,用來將 CommonJS 模塊轉(zhuǎn)換為 ES6,這樣它們就可以包含在 Rollup 包中) ?? @rollup/plugin-json(rollup 插件,它將.json 文件轉(zhuǎn)換為 ES6 模塊) ?? @rollup/plugin-node-resolve(rollup 插件,它使用節(jié)點(diǎn)解析算法定位模塊,用于在節(jié)點(diǎn)模塊中使用第三方 node_modules 包) ?? @rollup/plugin-typescript(rollup 插件,對(duì) typescript 的支持,將 typescript 進(jìn)行 tsc 轉(zhuǎn)為 js)

typescript 相關(guān)

?? typescript(使用 ts 開發(fā)工具庫) ?? tslib(TypeScript 的運(yùn)行庫,它包含了 TypeScript 所有的幫助函數(shù)) ?? @typescript-eslint/eslint-plugin(TypeScript 的 eslint 插件,約束 ts 書寫規(guī)范) ?? @typescript-eslint/parser(ESLint 解析器,它利用 TypeScript ESTree 來允許 ESLint 檢測(cè) TypeScript 源代碼)

文檔相關(guān)

?? typedoc(TypeScript 項(xiàng)目的文檔生成器) ?? gulp(使用 gulp 構(gòu)建文檔系統(tǒng)) ?? gulp-typedoc(Gulp 插件來執(zhí)行 TypeDoc 工具) ?? browser-sync(文檔系統(tǒng)熱更新)

單元測(cè)試相關(guān)

?? jest(一款優(yōu)雅、簡潔的 JavaScript 測(cè)試框架) ?? @types/jest(Jest 的類型定義) ?? ts-jest(一個(gè)支持源映射的 Jest 轉(zhuǎn)換器,允許您使用 Jest 來測(cè)試用 TypeScript 編寫的項(xiàng)目) ?? @babel/preset-typescript(TypeScript 的 Babel 預(yù)設(shè))

其他依賴

?? eslint(代碼規(guī)范約束) ?? @babel/core(@rollup/plugin-babel 依賴的 babel 解析插件) ?? @babel/plugin-transform-runtime(babel 轉(zhuǎn)譯依賴) ?? @babel/preset-env(babel 轉(zhuǎn)譯依賴) ?? chalk(控制臺(tái)字符樣式) ?? rimraf(UNIX 命令 rm -rf 用于 node) ?? cross-env(跨平臺(tái)設(shè)置 node 環(huán)境變量)

底層架構(gòu)搭建

1. 初始化項(xiàng)目

新建一個(gè)文件夾 utils-demo,執(zhí)行 npm init,過程會(huì)詢問構(gòu)建項(xiàng)目的基本信息,按需填寫即可:

npm init

2. 組織工具庫業(yè)務(wù)開發(fā) SRC 目錄結(jié)構(gòu)

創(chuàng)建工具庫業(yè)務(wù)開發(fā) src 文件目錄,明確怎樣規(guī)劃工具庫包,里面放置的是工具庫開發(fā)需要的業(yè)務(wù)代碼: c3b66f34-f41c-11ed-90ce-dac502259ad0.png

3. 安裝項(xiàng)目依賴

要對(duì) typescript 代碼進(jìn)行解析支持需要安裝對(duì) ts 支持的依賴,以及對(duì)開發(fā)的工具的一些依賴包:

yarn add typescript tslib rollup rollup-plugin-livereload rollup-plugin-serve rollup-plugin-terser rollup-plugin-visualizer 
@rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-json @rollup/plugin-node-resolve @rollup/plugin-typescript 
@babel/core @babel/plugin-transform-runtime @babel/preset-env rimraf lodash chalk@^4.1.2 -D
這里遇到一個(gè)坑,關(guān)于最新 chalk5.0.0 不支持在 nodejs 中 require () 導(dǎo)入,所以鎖定包版本 chalk@^4.1.2 要對(duì) typescript 進(jìn)行解析和編譯還需要配置 tsconfig.json,該文件中指定了用來編譯這個(gè)項(xiàng)目的根文件和編譯選項(xiàng),在項(xiàng)目根目錄,使用 tsc --init 命令快速生成 tsconfig.json 文件(前提全局安裝 typescript)
npm i typescript -g
tsc --init
初始化 tsconfig 完成之后,根目錄自動(dòng)生成 tsconfig.json 文件,需要對(duì)其進(jìn)行簡單的配置,以適用于 ts 項(xiàng)目,其中具體含義可以參考tsconfig.json官網(wǎng)

4. 組織項(xiàng)目打包構(gòu)建 SCRIPTS 目錄結(jié)構(gòu)

1) 根目錄創(chuàng)建項(xiàng)目打包構(gòu)建 scripts 腳本文件目錄,里面放置的是有關(guān)于項(xiàng)目打包構(gòu)建需要的文件: c3eb0d2a-f41c-11ed-90ce-dac502259ad0.png ??生成 rollup 配置項(xiàng)函數(shù)核心代碼:

const moduleName = camelCase(name) // 當(dāng)format為iife和umd時(shí)必須提供,將作為全局變量掛在window下:window.moduleName=...
const banner = generateBanner() // 包說明文案
// 生成rollup配置文件函數(shù)
const generateConfigs = (options) => {
  const { input, outputFile } = options
  console.log(chalk.greenBright(`獲取打包入口:${input}`))
  const result = []
  const pushPlugins = ({ format, plugins, ext }) => {
    result.push({
      input, // 打包入口文件
      external: [], // 如果打包出來的文件有項(xiàng)目依賴,可以在這里配置是否將項(xiàng)目依賴一起打到包里面還是作為外部依賴
      // 打包出口文件
      output: {
        file: `${outputFile}${ext}`, // 出口文件名稱
        sourcemap: true, // // 是否生成sourcemap
        format, // 打包的模塊化格式
        name: moduleName, // 當(dāng)format為iife和umd時(shí)必須提供,將作為全局變量掛在window下:window.moduleName=...
        exports: 'named' /** Disable warning for default imports */,
        banner, // 打包出來的文件在最頂部的說明文案
        globals: {} // 如果external設(shè)置了打包忽略的項(xiàng)目依賴,在此配置,項(xiàng)目依賴的全局變量
      },
      plugins // rollup插件
    })
  }
  buildType.forEach(({ format, ext }) => {
    let plugins = [...defaultPlugins]
    // 生產(chǎn)環(huán)境加入包分析以及代碼壓縮
    plugins = [
      ...plugins,
      visualizer({
        gzipSize: true,
        brotliSize: true
      }),
      terser()
    ]

    pushPlugins({ format, plugins, ext })
  })
return result
}


2) rollup 在打包構(gòu)建的過程中需要進(jìn)行 babel 的轉(zhuǎn)譯,需要在根目錄添加.babelrc 文件告知 babel:
{
  "presets": [
    [
      "@babel/preset-env"
    ]
  ],
  "plugins": ["@babel/plugin-transform-runtime"]
}

3) 此時(shí)距離打包構(gòu)建工具庫只差一步之遙,配置打包腳本命令,在 package.json 中配置命令:

"scripts": {
    "build": "rimraf lib && rollup -c ./scripts/rollup.config.js" // rollup打包
 },

4) 執(zhí)行 yarn build,根目錄會(huì)構(gòu)建出一個(gè) lib 文件夾,里面有打包構(gòu)建的文件,還多了一個(gè) stats.html,這個(gè)是可視化并分析 Rollup bundle,用來查看工具模塊占用空間:?

c41b578c-f41c-11ed-90ce-dac502259ad0.png ?架構(gòu)搭建優(yōu)化 項(xiàng)目搭建到這里,不知機(jī)智的你能否發(fā)現(xiàn)問題: 1) 只要添加了一個(gè)工具,就要在入口文件導(dǎo)出需要打包構(gòu)建的工具,在多人開發(fā)提交代碼的時(shí)候?qū)⒁齺頉_突的產(chǎn)生:? c43f7aa4-f41c-11ed-90ce-dac502259ad0.png 2) 使用工具庫的時(shí)候,按需引用的顆粒度太細(xì)了,不能滿足一些要求顆粒度粗的朋友,比如: ??我想使用該包里面 date 相關(guān)工具,要這樣嗎?

import { dateA, dateB, dateC } from "utils-demo"

能不能這樣?

import { date } from "utils-demo"
date.dateA()
date.dateB()
date.dateC()

?在一些使用 script 腳本引入的場(chǎng)景下,就僅僅需要 date 相關(guān)的工具,要這樣嗎?