# 建立项目文件件
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的开发走了一遍。
由于是第一遍完整的走感受仍是挺麻烦的。后续我也找找有没有相应的脚手架和工具。若是没有特别合适的考虑本身造一个这样的轮子。