基于TypeScript轴合,發(fā)布一個npm包

概述

npm包有什么用

有的同學在開發(fā)的過程中,經(jīng)常會造一些“輪子”平酿,也就是一些復用性比較強的庫(工具函數(shù)庫或者組件庫)凤优,那么將這些“輪子”發(fā)布成自己的一個npm包,絕對會給你帶來工作效率的提升蜈彼。

為什么用TypeScript

引用 TypeScrip教程 內(nèi)提及的內(nèi)容:

TypeScript 增加了代碼的可讀性和可維護性

  • 類型系統(tǒng)實際上是最好的文檔筑辨,大部分的函數(shù)看看類型的定義就可以知道如何使用了
  • 可以在編譯階段就發(fā)現(xiàn)大部分錯誤,這總比在運行時候出錯好
  • 增強了編輯器和 IDE 的功能幸逆,包括代碼補全棍辕、接口提示、跳轉(zhuǎn)到定義还绘、代碼重構(gòu)等

TypeScript 非常包容

  • TypeScript 是 JavaScript 的超集楚昭,.js 文件可以直接重命名為 .ts 即可
  • 即使不顯式的定義類型,也能夠自動做出類型推論
  • TypeScript 的類型系統(tǒng)是圖靈完備的拍顷,可以定義從簡單到復雜的幾乎一切類型
  • 即使 TypeScript 編譯報錯抚太,也可以生成 JavaScript 文件
  • 兼容第三方庫,即使第三方庫不是用 TypeScript 寫的昔案,也可以編寫單獨的類型文件供 TypeScript 讀取

其中凭舶,對于npm上的包來說。在使用包內(nèi)的工具時候爱沟,上述的接口提示就十分強大帅霜。

可以用JavaScript嗎

有些不會TypeScrip的同學可能說,這篇不適合我看呼伸。錯身冀!

本篇內(nèi)容也可以采用JavaScript的方式去寫,去發(fā)布使用括享。完全是適配的搂根。因為我們使用TypeScript,目的還是約束開發(fā)規(guī)范之類的問題铃辖,最終還是得通過打包成.js文件剩愧。如若用JavaScript的方式去寫,完全可以的娇斩,文末也會6.2處也會提及具體相關(guān)仁卷。上述:TypeScript 是 JavaScript 的超集穴翩,.js 文件可以直接重命名為 .ts 即可也能體現(xiàn)兩者的關(guān)系。

具體操作內(nèi)容

本文采用vue-cli3工具創(chuàng)建TypeScript項目锦积,目的是為了讓讀者更清晰看到自己寫的工具方法(寫組件同理)能及時的驗證芒帕,讓我們知悉在源碼編寫這一層面上是沒有問題。通過寫幾個簡單工具方法丰介,然后打包背蟆,發(fā)布到npm上,最后在項目中安裝自己發(fā)布的包哮幢。目的是:成功調(diào)用自己寫的包內(nèi)的方法带膀。

本文項目地址

github地址:https://github.com/chenjing0823/util-tools
npm包地址:https://www.npmjs.com/package/common-util-tools

操作步驟

1、創(chuàng)建項目

vue create util-tools

然后選擇Babel橙垢、Typescript垛叨、Unit TestingJest其余默認
運行項目后钢悲,正常打開vue默認頁后点额。項目創(chuàng)建完成舔株,可以繼續(xù)操作莺琳,關(guān)閉服務(wù)。

2载慈、目錄調(diào)整

之所以需要目錄調(diào)整惭等,是因為我們利用采用vue-cli3工具創(chuàng)建了TypeScript+vue的一個項目,其中在本項目內(nèi)办铡,我們只是要寫一個utils工具包辞做,而vue的頁面實例僅僅是用來校驗我們的工具是否可用可行。
所以目錄調(diào)整的目的寡具,是將包代碼合頁面實例代碼區(qū)分開秤茅。

    1. 在根同目錄下,創(chuàng)建一個example文件夾童叠,將src移動至改文件夾內(nèi)(頁面實例框喳,用于驗證方法,與工具包無關(guān))
    1. 在根目錄下創(chuàng)建src厦坛,用于放我們寫的工具包函數(shù)方法
    1. tsconfig.json內(nèi)五垮,需要修改以下內(nèi)容(新增3個example/src/)
{
// ...其他配置
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "example/src/**/*.ts",
    "example/src/**/*.tsx",
    "example/src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ]
// ...其他配置
}

3、源碼編寫

src/index.ts:

如果對于下面4個文件存在疑惑杜秸,且比較注重發(fā)布這個過程放仗,也可以直接在index.ts內(nèi)直接export自己寫的方法,不寫其他幾個文件方法撬碟。

import * as env from "./util-tool/env"; // 方法集合1
import * as is from "./util-tool/is"; // 方法集合2
import { Types } from "./types";
import { mixin } from "./tools/index";

function initUtils(): Types {
  const instance = Object.create(null);
  const arr = [env, is];
  mixin(instance, arr);

  return instance as Types;
}

const _utils = initUtils();

export default _utils;

src/util-tool/env

utils工具方法1

/**
 *
 * @ignore
 * @return {boolean} 判斷當前瀏覽器是移動端(false)還是pc端(true)
 *
 */
export function getEnv(): boolean {
  const userAgent = navigator.userAgent;
  const device: string[] = [
    "Android",
    "iPhone",
    "SymbianOS",
    "Windows Phone",
    "iPad",
    "iPod"
  ];
  let flag = true;
  for (let i = 0; i < device.length; i++) {
    if (userAgent.indexOf(device[i]) !== -1) {
      flag = false;
      break;
    }
  }
  return flag;
}

src/util-tool/is

utils工具方法2

export function isArray(value: any): value is Array<any> {
  return typeof value !== "undefined" && value instanceof Array;
}

export function isObject(value: any): value is Record<string, any> {
  return value !== null && typeof value === "object";
}

src/types

interface Env {
  /**
   *
   * 判斷當前瀏覽器是移動端還是pc端
   * @return {boolean} pc: true; mobile: false
   * @author superjing
   * ``` typescript
   * const env = utils.getEnv()
   * ```
   */
  getEnv(): boolean;
}

interface Is {
  /**
   *
   * 判斷是否是數(shù)組
   * @param value 傳入需要判斷的變量
   * @return {boolean} true | false
   * @author superjing
   * ``` typescript
   * utils.isArray([1, 2])    // true
   * ```
   *
   */
  isArray(value: any): boolean;
}
export interface Types extends Env, Is {}

tools/index

export function mixin<T, U>(to: T, from: Array<U>): T {
  from.forEach(obj => {
    Object.getOwnPropertyNames(obj).forEach(key => {
      to[key] = obj[key];
    });
  });
  return to;
}

4诞挨、項目配置

簡單的配置莉撇,易理解

/build/config.doc.js

該配置調(diào)試example文件夾中的頁面實例,在這個單頁面中可以直接使用以及測試編寫的工具方法

const path = require("path");
const resolve = dir => path.join(__dirname, "../", dir);

console.log("run doc");

module.exports = {
  publicPath: "./",
  devServer: { port: "8000" },
  outputDir: resolve("docs"),
  pages: {
    index: {
      entry: resolve("example/src/main.ts"),
      template: "public/index.html",
      filename: "index.html",
      title: "Index Page",
      chunks: ["chunk-vendors", "chunk-common", "index"]
    }
  },
  chainWebpack: config => {
    config.plugins.delete("prefetch-index");
  }
};

/build/config.lib.js

配置打包utils工具包亭姥,打包不包括example文件夾下的示例頁面稼钩,僅僅是index.ts中實現(xiàn)的函數(shù),打包目標為umd格式达罗,兼容瀏覽器坝撑,node以及es6模塊規(guī)范;

const path = require("path");
const resolve = dir => path.join(__dirname, "../", dir);

console.log("run lib");

module.exports = {
  outputDir: resolve("dist"),
  configureWebpack: {
    entry: {
      utils: resolve("src/index.ts")
    },
    output: {
      filename: `[name].js`,
      libraryTarget: "umd",
      libraryExport: "default",
      library: "utils",
      globalObject: "this"
    }
  },
  css: {
    extract: {
      filename: `[name].css`
    }
  },
  chainWebpack: config => {
    config.optimization.delete("splitChunks");
    config.plugins.delete("copy");
    config.plugins.delete("preload");
    config.plugins.delete("prefetch");
    config.plugins.delete("html");
    config.plugins.delete("hmr");
    config.entryPoints.delete("app");
  }
};

/build/index.js

module.exports =
  process.env.NODE_ENV === "production"
    ? require("./config.lib")
    : require("./config.doc");

/vue.config.js

module.exports = require("./build/index");

到這為止粮揉,配置完成巡李。下面進行工具調(diào)試

5、本地調(diào)試

/example/src/App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
  </div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import HelloWorld from "./components/HelloWorld.vue";
import utils from "@/index";

@Component({
  components: {
    HelloWorld
  }
})
export default class App extends Vue {
  mounted() {
    console.log(123);
    console.log("utils.isArray([]) is array is:", utils.isArray([]));
    console.log("utils.isArray('') is array is:", utils.isArray(""));
  }
}
</script>

下圖可以看到扶认,用typescript開發(fā)的提示功能
提示.png

啟動服務(wù)(確認4侨拦、項目配置無誤后,方可正常啟動)

npm run serve 

可以看到寫的工具可以正常使用:


本地工具調(diào)用結(jié)果.png

6辐宾、打包發(fā)布

6.1 打包

在4狱从、項目配置的config.lib.js內(nèi),已經(jīng)寫了打包相關(guān)內(nèi)容叠纹,運行打包命令

npm run build 

在目錄處生成dist文件夾季研,內(nèi)有生成的utils.js
同樣,在根目錄建一個demo.html誉察,直接引入打包生成的js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script src="./dist/utils.js"></script>
<script>
    console.log(123);
    console.log("utils.isArray([]) is array is:", utils.isArray([]));
    console.log("utils.isArray('') is array is:", utils.isArray(""));
</script>
</body>
</html>

調(diào)試結(jié)果.png

同樣可以正常使用与涡,于是工具包便算開發(fā)完成,可以自己發(fā)布了(若公司內(nèi)要規(guī)范npm的包持偏,還需要進行單元測試驼卖,我們構(gòu)建項目的時候已經(jīng)選擇了Unit Testing、Jest

6.2 發(fā)布

通過該文件鸿秆,其實也可以看到酌畜,若是用JavaScript寫該插件,也是極其方便的卿叽,只要把最后打包生成的js設(shè)為mian的入口即可桥胞。對typescript有不熟悉的,也可以用JavaScript進行開發(fā)
修改package.json

{
  "name": "common-util-tools", // 包名附帽,不能跟已有的包名有重復
  "version": "0.1.0", // 每次發(fā)布需要修改版本號
  "private": false, // 需要設(shè)置false
  "author": "chenjing0823",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test:unit": "vue-cli-service test:unit",
    "lint": "vue-cli-service lint"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/chenjing0823/util-tools"
  },
  "license": "MIT",
  "main": "dist/utils.js", // 入口需要正確
  "keywords": [
    "utils",
    "tools"
  ],
  "files": [
    "dist"
  ],
// ...其余代碼
}

然后發(fā)布(需要注冊npm賬戶埠戳,并先登陸自己的npm賬號發(fā)布)

npm publish

發(fā)布成功后,大概在短暫的延遲過后蕉扮,就可以在https://www.npmjs.com/搜到自己發(fā)布的插件了整胃。

npmjs查詢包.png

對于發(fā)布有問題的,可以參考發(fā)布npm包時遇到的一些坑

7喳钟、安裝調(diào)用

到上述為止屁使,包的創(chuàng)建在岂、編寫、發(fā)布已經(jīng)完成了蛮寂,現(xiàn)在來試用一下試試:

7.1 新建一個空文件夾

在該文件夾下init生成一個空項目

npm init -y

7.2 安裝我們的包

npm install common-util-tools -D

可以在package.json內(nèi)看到:


image.png

7.3 新建一個index.js

const utils = require('common-util-tools')
console.log(123);
console.log("utils.isArray([]) is array is:", utils.isArray([]));
console.log("utils.isArray('') is array is:", utils.isArray(""));

7.4 使用測試

node index.js
使用結(jié)果.png

到此蔽午,我們從創(chuàng)建項目 - > 編寫代碼 - > 項目配置 - > 打包發(fā)布 - > 包的使用,已經(jīng)大功告成酬蹋,后續(xù)讀者朋友就可以寫出自己的一套東西去發(fā)布使用及老。例如一些公共組件的編寫,公共方法的編寫范抓。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骄恶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子匕垫,更是在濱河造成了極大的恐慌僧鲁,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件象泵,死亡現(xiàn)場離奇詭異寞秃,居然都是意外死亡,警方通過查閱死者的電腦和手機偶惠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門春寿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洲鸠,你說我怎么就攤上這事堂淡〔雒澹” “怎么了扒腕?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長萤悴。 經(jīng)常有香客問我瘾腰,道長,這世上最難降的妖魔是什么覆履? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任蹋盆,我火速辦了婚禮,結(jié)果婚禮上硝全,老公的妹妹穿的比我還像新娘栖雾。我一直安慰自己,他們只是感情好伟众,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布析藕。 她就那樣靜靜地躺著,像睡著了一般凳厢。 火紅的嫁衣襯著肌膚如雪账胧。 梳的紋絲不亂的頭發(fā)上竞慢,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音治泥,去河邊找鬼筹煮。 笑死,一個胖子當著我的面吹牛居夹,可吹牛的內(nèi)容都是我干的败潦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼准脂,長吁一口氣:“原來是場噩夢啊……” “哼变屁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起意狠,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤粟关,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后环戈,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闷板,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年院塞,在試婚紗的時候發(fā)現(xiàn)自己被綠了遮晚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡拦止,死狀恐怖县遣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情汹族,我是刑警寧澤萧求,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站顶瞒,受9級特大地震影響夸政,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜榴徐,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一守问、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坑资,春花似錦耗帕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春探越,著一層夾襖步出監(jiān)牢的瞬間狡赐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工钦幔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留枕屉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓鲤氢,卻偏偏與公主長得像搀擂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子卷玉,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容