第三部分 - 打包篇:項目打包,併發布至 NPM
原文連接css
在前面的部分,咱們使用 React 等相關技術構建了庫並對其進行了測試。如今,咱們準備對前面的代碼進行打包,並將其發佈至 NPM,方便其餘人使用。node
本篇文章,是這個系列的第三篇::項目打包,併發布至 NPMreact
組件庫開發到了這裏,終於也到了最重要的部分,解決(文檔 + 打包)的問題。webpack
在嘗試了一些打包庫(好比create-react-library),和文檔庫(React Styleguidist)以後,都沒有達到想要的效果。git
直到B站的一個視頻:利用 umi-library 作組件打包,答案就變得簡單而明顯了,就是利用雲謙大大開源的組件打包利器:umijs/father,來完成最後一步。es6
由於目前整個打包工具會把src
做爲入口。爲了不前面路由,首頁等代碼被打包進去,這裏對項目結構作出了較大的改動,新增長了 entry
做爲路由的入口,而 src
則做爲組件的入口。建議參考下 dantd 中的目錄結構。github
項目初始化以後,接下來,用編輯器打開這個項目,並修改 package.json
中下面屬性:web
{ "main": "lib/index.js", "module": "es/index.js", "typings": "lib/index.d.ts",c "files": [ "dist", "lib", "es" ], "scripts": { "start": "father doc dev", "doc:build": "father doc build", "doc:deploy": "father doc deploy", "lib:build": "father build" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0", "antd": ">=3.21.0" }, "devDependencies": { "babel-plugin-import": "^1.13.0", "father": "^2.29.2", "fs-extra": "^8.1.0", "klaw-sync": "^6.0.0" }, "dependencies": { "antd": "^3.21.0", "classnames": "^2.2.6", "lodash": "^4.17.15" }, }
添加好以後,運行:npm install
安裝依賴。在等待的同時,讓咱們瞭解一下上述屬性的具體含義:npm
npm
包的入口文件,browser 環境和 node 環境都可使用npm
包的 ESM 規範的入口文件,browser 環境和 node 環境都可使用上面兩個都是程序的入口,當咱們使用打包工具(webpack)進行打包的時候:一、若是它已經支持 pkg.module 字段則會優先使用 ES6 模塊規範的版本 import,這樣能夠啓用 Tree Shaking 機制。二、若是它還不識別 pkg.module 字段則會使用咱們已經編譯成 CommonJS 規範的版本 require('package1'),也不會阻礙打包流程。
Antd
進行簡單封裝的,因此,在使用這個組件庫的時候,也須要安裝對應版本的 Antd
等依賴。這裏,咱們來給:EmptyLine
加上文檔便可。爲了方便閱讀,這裏仍是放上了組件的全部相關代碼。json
export { default as EmptyLine } from './empty-line';
import './style/index.less'; import EmptyLine from './EmptyLine'; export default EmptyLine;
--- name: EmptyLine route: /empty-line menu: 組件 --- import { Playground } from 'docz'; import EmptyLine from './index'; ## EmptyLine > 組件名稱:空行(EmptyLine),自定義組件 ,寬度 100% ### 代碼演示 #### 複製信息 <Playground> <p>第一行文字</p> <EmptyLine /> <p>第二行文字</p> </Playground> ## API |參數|說明|類型|默認值| |:--|:--|:--|:--| |height|空行的高度|number?|20|
import React from 'react'; import './style/index.less'; export interface IEmptyLineProps { height?: number; } const EmptyLine = ({ height = 20 }: IEmptyLineProps) => { return <div className="empty-line" style={{ height }} />; }; export default EmptyLine;
.empty-line { width: 100%; height: 20px; }
export default { // cssModules: true, // 默認是 .module.css 走 css modules,.css 不走 css modules。配置 cssModules 爲 true 後,所有 css 文件都走 css modules。(less 文件同理) extractCSS: true, esm: 'babel', cjs: 'babel', umd: { name: 'dantd', sourcemap: true, globals: { react: 'React', antd: 'antd' }, }, extraBabelPlugins: [ ['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }], ], entry: 'src/index.tsx', lessInBabelMode: true, doc: { base: '/dantd/', menu: [ '首頁', '組件' ] }, }
更多配置項,歡迎探索文檔:umijs/father
{ "compilerOptions": { "baseUrl": "./src", "paths": { "antd": ["src/index.tsx"], "antd/es/*": ["src/*"] }, "strictNullChecks": true, "moduleResolution": "node", "esModuleInterop": true, "experimentalDecorators": true, "jsx": "preserve", "noUnusedParameters": true, "noUnusedLocals": false, "noImplicitAny": true, "target": "es6", "lib": ["dom", "es2017"], "skipLibCheck": true }, "exclude": ["node_modules", "lib", "es"] }
添加這些文件以後,運行 npm start
,就能夠看到下面的界面了。
若是想引入 Antd
,直接引入就行,上面的配置中,已經增長了:extraBabelPlugins
。能夠按需加載 antd。
組件中引入代碼:
import { Card, Typography } from 'antd';
ES6 打包代碼:
import "antd/es/card/style"; import _Card from "antd/es/card"; import "antd/es/typography/style"; import _Typography from "antd/es/typography";
CommonJS 打包代碼:
require("antd/es/card/style"); var _card = _interopRequireDefault(require("antd/es/card")); require("antd/es/typography/style"); var _typography = _interopRequireDefault(require("antd/es/typography"));
首先,運行 father build
打包代碼。
能夠看到,father
會分別根據:umd、cjs、es 這三種格式進行打包,打包以後會看到多出了下面這些文件。
├── dist | ├── empty-line | | ├── EmptyLine.d.ts | | ├── index.d.ts | | └── style | | └── index.d.ts | ├── index.d.ts | ├── index.umd.css | ├── index.umd.js | ├── index.umd.js.map | ├── index.umd.min.css | ├── index.umd.min.js | └── index.umd.min.js.map ├── es | ├── empty-line | | ├── EmptyLine.js | | ├── index.js | | └── style | | ├── index.css | | └── index.js | └── index.js ├── lib | ├── empty-line | | ├── EmptyLine.js | | ├── index.js | | └── style | | ├── index.css | | └── index.js | └── index.js
此時,能夠看到三種類型的包,已經被成功打出來了。那是否是這個時候就能夠上傳至 npm
了呢?
還不行,對比 Antd
的 npm
包以後,會發現 es
和 lib
兩個目錄下,尚未類型文件。須要將 dist
目錄下的文件拷貝過來,並把文件中的 .less
改爲 .css
。這裏準備寫2個腳本 hack 一下。
安裝依賴:
npm install klaw-sync fs-extra -D
增長2個腳本:
const path = require('path'); const klawSync = require('klaw-sync'); const fs = require('fs'); const filesRegex = /.d.ts$/; const declarePaths = klawSync(path.resolve(__dirname, '../dist'), { nodir: true }).filter(pathItem => filesRegex.test(pathItem.path)) declarePaths.forEach((pathItem) => { const esPath = pathItem.path.replace('/dist', '/es'); const libPath = pathItem.path.replace('/dist', '/lib'); fs.copyFileSync(pathItem.path, esPath); fs.copyFileSync(pathItem.path, libPath); }) console.log('.d.ts 文件拷貝成功!');
const path = require('path'); const klawSync = require('klaw-sync'); const fs = require('fs'); const filesRegex = /(.js|.d.ts)$/; const fileFilterFn = item => { const basename = path.basename(item.path); return filesRegex.test(basename) || basename.indexOf('.') < 0; } const esPaths = klawSync(path.resolve(__dirname, '../es'), { filter: fileFilterFn, nodir: true }).map(item => item.path) const libPaths = klawSync(path.resolve(__dirname, '../lib'), { filter: fileFilterFn, nodir: true }).map(item => item.path) const allPaths = esPaths.concat(libPaths); allPaths.forEach((fileItem) => { const fileContent = fs.readFileSync(fileItem, 'utf8'); const newFileContent = fileContent.replace(/.less/gi, '.css'); fs.writeFileSync(fileItem, newFileContent, 'utf8'); }) console.log('.less => .css 文件後綴改寫成功!');
修改打包命令:
"build": "father build && node ./scripts/moveDeclare.js && node ./scripts/changeLess2Css.js"
運行:npm run build
此次打包以後的文件,就能夠上傳至 npm
了。
首先登錄 npm
:
使用 git 提交全部代碼,而後修改版本號,併發布代碼:
npm version patch git push npm publish
這裏若是包名已經被註冊,或者npm源不對,會報403錯誤,須要自行處理下
到了這裏,咱們的第一個屬於本身的組件庫就被上傳至 npm
了,咱們可使用:npm install dantd
下載咱們的安裝包,並在項目中使用裏面的組件了。
首先,在 package.json
文件中,添加 git
地址,便於以後文檔的發佈:
"repository": { "type": "git", "url": "https://github.com/jokingzhang/dantd" },
運行下面命令打包文檔:
npm run doc:build
運行下面命令發佈文檔:
npm run doc:deploy
而後訪問對應的地址就能夠看到咱們發佈到線上的組件文檔了:dantd
屬於咱們本身的第一個組件庫,就這樣被髮布到 npm
了。🎉🎉🎉 可是,這個組件庫須要寫哪些組件進去,是咱們接下來須要考慮的。
若是您喜歡這個系列,歡迎評論,分享文章連接。此外,也歡迎多多吐槽,🙏 這些反饋對我來講是很是寶貴的,以便我未來寫出更優秀的文章。