概述
npm包有什么用
有的同學在開發的過程中,經常會造一些“輪子”,也就是一些復用性比較強的庫(工具函數庫或者組件庫),那么將這些“輪子”發布成自己的一個npm包,絕對會給你帶來工作效率的提升。
為什么用TypeScript
引用 TypeScrip教程 內提及的內容:
TypeScript 增加了代碼的可讀性和可維護性
- 類型系統實際上是最好的文檔,大部分的函數看看類型的定義就可以知道如何使用了
- 可以在編譯階段就發現大部分錯誤,這總比在運行時候出錯好
- 增強了編輯器和 IDE 的功能,包括代碼補全、接口提示、跳轉到定義、代碼重構等
TypeScript 非常包容
- TypeScript 是 JavaScript 的超集,
.js
文件可以直接重命名為.ts
即可- 即使不顯式的定義類型,也能夠自動做出類型推論
- TypeScript 的類型系統是圖靈完備的,可以定義從簡單到復雜的幾乎一切類型
- 即使 TypeScript 編譯報錯,也可以生成 JavaScript 文件
- 兼容第三方庫,即使第三方庫不是用 TypeScript 寫的,也可以編寫單獨的類型文件供 TypeScript 讀取
其中,對于npm上的包來說。在使用包內的工具時候,上述的接口提示就十分強大。
可以用JavaScript嗎
有些不會TypeScrip的同學可能說,這篇不適合我看。錯!
本篇內容也可以采用
JavaScript
的方式去寫,去發布使用。完全是適配的。因為我們使用TypeScript
,目的還是約束開發規范之類的問題,最終還是得通過打包成.js
文件。如若用JavaScript
的方式去寫,完全可以的,文末也會6.2處也會提及具體相關。上述:TypeScript 是 JavaScript 的超集,.js 文件可以直接重命名為 .ts 即可也能體現兩者的關系。
具體操作內容
本文采用vue-cli3
工具創建TypeScript
項目,目的是為了讓讀者更清晰看到自己寫的工具方法(寫組件同理)能及時的驗證,讓我們知悉在源碼編寫這一層面上是沒有問題。通過寫幾個簡單工具方法,然后打包,發布到npm上,最后在項目中安裝自己發布的包。目的是:成功調用自己寫的包內的方法。
本文項目地址
github地址:https://github.com/chenjing0823/util-tools
npm包地址:https://www.npmjs.com/package/common-util-tools
操作步驟
1、創建項目
vue create util-tools
然后選擇Babel
、Typescript
、Unit Testing
、Jest
其余默認
運行項目后,正常打開vue默認頁后。項目創建完成,可以繼續操作,關閉服務。
2、目錄調整
之所以需要目錄調整,是因為我們利用采用vue-cli3
工具創建了TypeScript
+vue
的一個項目,其中在本項目內,我們只是要寫一個utils
工具包,而vue的頁面實例僅僅是用來校驗我們的工具是否可用可行。
所以目錄調整的目的,是將包代碼合頁面實例代碼區分開。
- 在根同目錄下,創建一個example文件夾,將src移動至改文件夾內(頁面實例,用于驗證方法,與工具包無關)
- 在根目錄下創建src,用于放我們寫的工具包函數方法
- tsconfig.json內,需要修改以下內容(新增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個文件存在疑惑,且比較注重發布這個過程,也可以直接在index.ts內直接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 {
/**
*
* 判斷是否是數組
* @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
該配置調試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中實現的函數,打包目標為umd格式,兼容瀏覽器,node以及es6模塊規范;
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");
到這為止,配置完成。下面進行工具調試
5、本地調試
/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開發的提示功能啟動服務(確認4、項目配置無誤后,方可正常啟動)
npm run serve
可以看到寫的工具可以正常使用:
6、打包發布
6.1 打包
在4、項目配置的config.lib.js
內,已經寫了打包相關內容,運行打包命令
npm run build
在目錄處生成dist
文件夾,內有生成的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>
同樣可以正常使用,于是工具包便算開發完成,可以自己發布了(若公司內要規范npm的包,還需要進行單元測試,我們構建項目的時候已經選擇了
Unit Testing、Jest
)
6.2 發布
通過該文件,其實也可以看到,若是用JavaScript
寫該插件,也是極其方便的,只要把最后打包生成的js設為mian的入口即可。對typescript
有不熟悉的,也可以用JavaScript
進行開發
修改package.json
{
"name": "common-util-tools", // 包名,不能跟已有的包名有重復
"version": "0.1.0", // 每次發布需要修改版本號
"private": false, // 需要設置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"
],
// ...其余代碼
}
然后發布(需要注冊npm賬戶,并先登陸自己的npm賬號發布)
npm publish
發布成功后,大概在短暫的延遲過后,就可以在https://www.npmjs.com/搜到自己發布的插件了。
對于發布有問題的,可以參考發布npm包時遇到的一些坑
7、安裝調用
到上述為止,包的創建、編寫、發布已經完成了,現在來試用一下試試:
7.1 新建一個空文件夾
在該文件夾下init生成一個空項目
npm init -y
7.2 安裝我們的包
npm install common-util-tools -D
可以在package.json內看到:
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
到此,我們從創建項目 - > 編寫代碼 - > 項目配置 - > 打包發布 - > 包的使用,已經大功告成,后續讀者朋友就可以寫出自己的一套東西去發布使用。例如一些公共組件的編寫,公共方法的編寫。