# 建立項目文件件
mkdir sourcemap-stacktrack-parser
# 建立README.md文件
echo "# sourcemap-stacktrack-parser" >> README.md
複製代碼
git init
# 添加README文件
git add README.md
# 提交代碼
git commit -m "first commit"
# 設置遠程倉庫地址
git remote add origin git@github.com:su37josephxia/sourcemap-stacktrack-parser.git
# 推送代碼
git push -u origin master
複製代碼
npm init -y
複製代碼
npm i typescript ts-node-dev @types/node -d
複製代碼
{
"compilerOptions": {
"outDir": "./lib",
"target": "es2017",
"module": "commonjs",//組織代碼方式
"sourceMap": true,
"moduleResolution": "node", // 模塊解決策略
"experimentalDecorators": true, // 開啓裝飾器定義
"allowSyntheticDefaultImports": true, // 容許es6方式import
"lib": ["es2015"],
"typeRoots": ["./node_modules/@types"],
},
"include": ["src/**/*"]
}
複製代碼
mkdir src
echo 'console.log("helloworld")' >> src/index.ts
複製代碼
在package.json文件中添加node
"scripts": {
"start": "ts-node-dev ./src/index.ts -P tsconfig.json --no-cache",
"build": "tsc -P tsconfig.json",
}
複製代碼
修改package.json中webpack
{
...
"main": "lib/index.js",
...
}
複製代碼
npm start
複製代碼
npm install jest ts-jest @types/jest -d
複製代碼
{
"transform": {
"^.+\\.(t|j)sx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
}
複製代碼
{
"scripts": {
"test": "jest --config jestconfig.json --coverage",
}
}
複製代碼
export const add = (a: number, b: number) => a + b
複製代碼
在src/___tests___文件夾中建立index.spec.tsgit
import { add } from "../index";
test("Index add fun", () => {
const ret = add(1, 2)
console.log(ret)
expect(ret).toBe(3);
});
複製代碼
npm run test
複製代碼
安裝eslint包es6
npm install prettier tslint tslint-config-prettier -d
複製代碼
配置tslint.jsongithub
{
"extends": ["tslint:recommended", "tslint-config-prettier"],
"rules": {
"no-console": false, // 忽略console.log
"object-literal-sort-keys": false,
"member-access": false,
"ordered-imports": false
},
"linterOptions": {
"exclude": ["**/*.json", "node_modules"]
}
}
複製代碼
Prettier 是格式化代碼工具。用來保持團隊的項目風格統一。web
{
"trailingComma": "all",
"tabWidth": 4,
"semi": false,
"singleQuote": true,
"endOfLine": "lf",
"printWidth": 120,
"overrides": [
{
"files": ["*.md", "*.json", "*.yml", "*.yaml"],
"options": {
"tabWidth": 2
}
}
]
}
複製代碼
「EditorConfig幫助開發人員在不一樣的編輯器和IDE之間定義和維護一致的編碼樣式。EditorConfig項目由用於定義編碼樣式的文件格式和一組文本編輯器插件組成,這些插件使編輯器可以讀取文件格式並遵循定義的樣式。EditorConfig文件易於閱讀,而且與版本控制系統配合使用。typescript
對於VS Core,對應的插件名是EditorConfig for VS Codenpm
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
[{*.json,*.md,*.yml,*.*rc}]
indent_style = space
indent_size = 2
複製代碼
添加script腳本json
{
"scripts": {
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
"lint": "tslint -p tsconfig.json"
}
}
複製代碼
npm install husky -d
複製代碼
{
"hooks": {
"pre-commit": "npm run format && npm run lint && npm test"
}
}
複製代碼
Travis CI 提供的是持續集成服務,它僅支持 Github,不支持其餘代碼託管。它須要綁定 Github 上面的項目,還須要該項目含有構建或者測試腳本。只要有新的代碼,就會自動抓取。而後,提供一個虛擬機環境,執行測試,完成構建,還能部署到服務器。只要代碼有變動,就自動運行構建和測試,反饋運行結果。確保符合預期之後,再將新代碼集成到主幹。緩存
這個項目須要Travis在提交後自動進行測試而且向codecov提供測試報告。
登陸https://www.travis-ci.org/網站
使用github帳號登陸系統
運行自動化測試框架
language: node_js # 項目語言,node 項目就按照這種寫法就OK了
node_js:
- 13.2.0 # 項目環境
cache: # 緩存 node_js 依賴,提高第二次構建的效率
directories:
- node_modules
test:
- npm run test # 運行自動測試框架
複製代碼
參考教程:Travis CI Tutorial
經過github帳號登陸travis
將上面 URL 中的 {GitHub 用戶名} 和 {項目名稱} 替換爲本身項目的便可,最後能夠將集成完成後的 markdown 代碼貼在本身的項目上
http://img.shields.io/travis/{GitHub 用戶名}/{項目名稱}.svg
複製代碼
Codecov是一個開源的測試結果展現平臺,將測試結果可視化。Github上許多開源項目都使用了Codecov來展現單測結果。Codecov跟Travis CI同樣都支持Github帳號登陸,一樣會同步Github中的項目。
npm install codecov -d
複製代碼
在package.json添加codecov
{
...,
"scripts": {
...,
"codecov": "codecov"
}
}
複製代碼
在travis.yaml中添加
after_success: # 構建成功後的自定義操做
- npm run codecov # 生成 Github 首頁的 codecov 圖標
複製代碼
將圖標嵌入到README.md之中
[](https://codecov.io/gh/<Github Username>/<Repository Name>/)
複製代碼
最後獲取測試經過圖標
這個庫的功能須要將js錯誤的調用棧中的壓縮代碼位置轉換爲源碼位置。固然要藉助sourcemap的幫忙。因此輸入數據分別是errorstack和sourcemap。
首先把測試用的sourcemap放入src/__test__目錄中
而後編寫測試用例index.spec.ts
import StackParser from "../index"
const { resolve } = require('path')
const error = {
stack: 'ReferenceError: xxx is not defined\n' +
' at http://localhost:7001/public/bundle.e7877aa7bc4f04f5c33b.js:1:1392\n' +
' at http://localhost:7001/public/bundle.e7877aa7bc4f04f5c33b.js:1:1392',
message: 'Uncaught ReferenceError: xxx is not defined',
filename: 'http://localhost:7001/public/bundle.e7877aa7bc4f04f5c33b.js'
}
describe('parseStackTrack Method:', () => {
it("測試Stack轉換爲StackFrame對象", () => {
expect(StackParser.parseStackTrack(error.stack, error.message))
.toContainEqual(
{
columnNumber: 1392,
lineNumber: 1,
fileName: 'http://localhost:7001/public/bundle.e7877aa7bc4f04f5c33b.js',
source: ' at http://localhost:7001/public/bundle.e7877aa7bc4f04f5c33b.js:1:1392'
})
})
})
describe('parseOriginStackTrack Method:', () => {
it("正常測試", async () => {
const parser = new StackParser(resolve(__dirname, './data'))
const originStack = await parser.parseOriginStackTrack(error.stack, error.message)
// 斷言
expect(originStack[0]).toMatchObject(
{
source: 'webpack:///src/index.js',
line: 24,
column: 4,
name: 'xxx'
}
)
})
it("sourcemap文件不存在", async () => {
const parser = new StackParser(resolve(__dirname, './xxx'))
const originStack = await parser.parseOriginStackTrack(error.stack, error.message)
// 斷言
expect(originStack[0]).toMatchObject(
{
columnNumber: 1392,
lineNumber: 1,
fileName: 'http://localhost:7001/public/bundle.e7877aa7bc4f04f5c33b.js',
source: ' at http://localhost:7001/public/bundle.e7877aa7bc4f04f5c33b.js:1:1392'
}
)
})
})
複製代碼
const ErrorStackParser = require('error-stack-parser')
const { SourceMapConsumer } = require('source-map')
const path = require('path')
const fs = require('fs')
export default class StackParser {
private sourceMapDir: string
private consumers: Object
constructor(sourceMapDir) {
this.sourceMapDir = sourceMapDir
this.consumers = {}
}
/** * 轉換錯誤對象 * @param stack 堆棧字符串 * @param message 錯誤信息 */
static parseStackTrack(stack: string, message?: string) {
const error = new Error(message)
error.stack = stack
const stackFrame = ErrorStackParser.parse(error)
return stackFrame
}
/** * 轉換錯誤對象 * @param stack 堆棧字符串 * @param message 錯誤信息 */
parseOriginStackTrack(stack: string, message?: string) {
const frame = StackParser.parseStackTrack(stack,message)
return this.getOriginalErrorStack(frame)
}
/** * 轉換源代碼運行棧 * @param stackFrame 堆棧片斷 */
async getOriginalErrorStack(stackFrame: Array<Object>) {
const origin = []
for (let v of stackFrame) {
origin.push(await this.getOriginPosition(v))
}
return origin
}
/** * 轉換源代碼運行棧 * @param stackFrame 堆棧片斷 */
async getOriginPosition(stackFrame) {
let { columnNumber, lineNumber, fileName } = stackFrame
fileName = path.basename(fileName)
// 判斷consumer是否存在
let consumer = this.consumers[fileName]
if (consumer === undefined) {
// 讀取sourcemap
const sourceMapPath = path.resolve(this.sourceMapDir, fileName + '.map')
// 判斷文件是否存在
if (!fs.existsSync(sourceMapPath)) {
return stackFrame
}
const content = fs.readFileSync(sourceMapPath, 'utf-8')
// console.log('content',content)
consumer = await new SourceMapConsumer(content, null)
this.consumers[fileName] = consumer
}
const parseData = consumer.originalPositionFor({line:lineNumber,column:columnNumber})
return parseData
}
}
複製代碼
npm run dev
複製代碼
每一個開源項目都須要配置一份合適的開源許可證來告知全部瀏覽過咱們的項目的用戶他們擁有哪些權限,具體許可證的選取能夠參照阮一峯前輩繪製的這張圖表:
那咱們又該怎樣爲咱們的項目添加許可證了?其實 Github 已經爲咱們提供了很是簡便的可視化操做: 咱們平時在逛 github 網站的時候,發現很多項目都在 README.md 中添加徽標,對項目進行標記和說明,這些小圖標給項目增色很多,不只簡單美觀,並且還包含清晰易懂的信息。
能夠參考README最佳實踐
參考https://github.com/jehna/readme-best-practices/blob/master/README-default.md
以前已經添加了travisci的build圖標和codecov的覆蓋率圖表。
若是想繼續豐富圖標給本身的項目增光登陸
shields.io/ 這個網站
好比以添加github的下載量爲例
每一個開源項目都須要配置一份合適的開源許可證來告知全部瀏覽過咱們的項目的用戶他們擁有哪些權限,具體許可證的選取能夠參照阮一峯前輩繪製的這張圖表:
那咱們又該怎樣爲咱們的項目添加許可證了?其實 Github 已經爲咱們提供了很是簡便的可視化操做: 咱們平時在逛 github 網站的時候,發現很多項目都在 README.md 中添加徽標,對項目進行標記和說明,這些小圖標給項目增色很多,不只簡單美觀,並且還包含清晰易懂的信息。
publish.sh
#!/usr/bin/env bash
npm config get registry # 檢查倉庫鏡像庫
npm config set registry=http://registry.npmjs.org
echo '請進行登陸相關操做:'
npm login # 登錄
echo "-------publishing-------"
npm publish # 發佈
npm config set registry=https://registry.npm.taobao.org # 設置爲淘寶鏡像
echo "發佈完成"
exit
複製代碼
執行發佈
./publish.sh
複製代碼
填入github用戶名密碼後
登陸https://www.npmjs.com/~josephxia
就能夠看到本身的第一個開源做品誕生啦。
基本上把開源過程和TDD的開發走了一遍。
由於是第一遍完整的走感受仍是挺麻煩的。後續我也找找有沒有相應的腳手架和工具。若是沒有特別合適的考慮本身造一個這樣的輪子。