内容简介:首先在npm官网进行注册登录运行
开发流程
初始化
首先在npm官网进行注册登录
运行 npm init
,可以通过命令行进行一些初始化的设置,如果想快速进行设置,可以运行 npm init -y
,会在项目的根目录生成一个package.json的文件,具体包含哪些配置可以参考官方文档,下面介绍一些常用的配置。
-
name:npm包的名称
-
version:包的版本号
-
description:对包的功能进行描述
-
main:包的入口文件,默认是index.js
-
repository:代码的托管信息,一般是github地址
-
keywords:关键字信息,便于包的搜索
-
author:作者
-
license:开源协议,一般是MIT和ISC
-
bugs:提bug的页面,默认是github的issue页面
-
homepage:项目的主页
最好增加README.md,用来对项目进行简单的说明,比如如何安装使用,以及一些api的介绍和例子。
在代码开发完成以后,在命令行进行npm登陆 npm login
。
最后使用 npm publish
对包进行发布。
代码规范
使用eslint,对JavaScript的书写规范做一定的限制,可以在一些通过配置的基础上增加一些团队自己的限制项。
使用stylelint对样式文件做一些规范化的工作,也可以根据团队的需要做一些定制化。
使用.editorconfig来配置编辑器的规范,保证缩进和换行等的一致性。
SemVer
SemVer的中文名称是语义化版本控制规范。npm默认使用SemVer来进行模块的版本控制。一个发布到npm的包要严格遵守SemVer的版本规范,不然会发布失败。
版本格式
主版本号.次版本号.修订号,可以用x.y.z的写法来简单表示。
-
修订号(patch):只有在做了向下兼容的修正时才可以递增,可以理解为bug fix版本
-
次版本号(minor):只有在新增了可以向下兼容的新功能的时候,才可以递增,可以理解为feature版本。
-
主版本号(major):只有在新增了无法向下兼容的API的时候,才可以递增。
先行版本
当要进行大版本迭代的时候,或者增加一些核心的功能,但又不能保证新版本百分之百正常,这个时候就可以发布先行版本。SemVer规范中使用alpha、beta和rc来修饰先行版本。
-
alpha:内部版本
-
beta:公测版本
-
rc:Release candiate,正式版本的候选版本
先行版本的版本号可以使用:1.0.0-alpha、1.0.0-beta.1、1.0.0- rc.1、1.0.0-0.3.7等。
版本号的优先级
进行版本号比较时,x、y、z依次比较
先行版本号的规则是rc > beta > alpha
1.0.0 < 2.0.0 < 2.1.0 < 2.1.1 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0- rc.1 < 1.0.0复制代码
更多内容可以看SemVer
husky & lint-staged
在项目中需要单测和对代码规范的校验,如果每次修改,都对项目的所有代码进行校验,会有性能和时间上的浪费;还有如果老项目没有接入单测和代码规范,那么如果对所有的代码都进行校验的话,会导致错误太多无法提交代码。现在项目中已经使用的方案是husky & lint-staged。
husky在安装的时候,会执行这个包的npm install这个script,对项目的Git钩子进行重写,我们就可以在git的钩子函数中做一些代码方面的校验工作。lint-staged这个库只会新加入暂存区的文件进行相关的操作,这样就可以优化触发操作的文件范围。
package.json { ... "scripts": { "lint": "eslint --fix src/", "lint:style": "stylelint --fix 'src/**/*.less'", "test": "cross-env BABEL_ENV=test jest --colors --config .jest.js", "pre-commit": "lint-staged" }, "lint-staged": { "ignore": [ "build/*", "node_modules" ], "linters": { "src/*.js": [ "eslint --fix", "git add" ], "src/**/*.less": [ "stylelint --fix", "git add" ], "src/components/**/*.js": [ "jest --findRelatedTests --config .jest.js", "git add" ], "src/utils/*.js": [ "jest --findRelatedTests --config .jest.js", "git add" ] } } ... } 复制代码
git commit & changelog
规范化commit信息,有助于将修改的问题进行分类,快速定位修复的问题,并提取出有用的提交信息来生成最终的changelog文件。
社区中比较好的方案是commitizen和conventional-changelog。
commitizen
commitizen
用来规范commit message,比较主流是的是使用AngularJS的规范来编写commit message。
全局安装commitizen
sudo npm install -g commitizen复制代码
然后在项目里执行下面的语句,让commitizen支持AngularJS的message规范。
commitizen init cz-conventional-changelog --save-dev --save-exact复制代码
执行以后,会在项目的devDependencies加入cz-conventional-changelog这个依赖,并在package.json中加入如下的配置项
"config": { "commitizen": { "path": "cz-conventional-changelog" } }复制代码
完成上面的步骤以后,以后所有的git commit 命令都用git cz来替换。
AngularJS的提交风格如下
<type>(<scope>): <subject> // 空一行 <body> // 空一行 <footer>复制代码
由Header、Body和Footer三个部分组成,其中Header是必须的,Body和Footer都可以省略。
-
type表示commit的类型,有如下七种类型:
-
feat:新功能(feature)
-
fix:修补bug
-
docs:文档(documentation)
-
style: 格式(不影响代码运行的变动)
-
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
-
test:增加测试
-
chore:构建过程或辅助 工具 的变动
-
-
scope表示这次commit的影响范围
-
subject是commit的简单描述,不能超过50个字符
-
body是对这次commit的具体描述,可以是多行的
-
footer只用于两种情况
-
不兼容变动,如果是上个版本不兼容的改动,用BREAKING CHANGE作为开头
-
关闭 Issue,例如 Closes #234
-
生成changelog
如果所有的提交记录都符合AngularJS的规范,那么可以使用命令来自动生成changelog文件。
必须安装conventional-changelog-cli的依赖 npm install --save-dev conventional-changelog-cli { "scripts": { "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0" } }复制代码
生成的文档只会收集type为feat、fix还有Breaking changes这三种类型的提交记录。
如果强制使用的话,可以 validate-commit-msg 来对commit message进行校验,如果格式不符合,就阻止提交。
如果不想使用规范化的提交,也可以使用下面的方法,收集所有的提交信息来生changelog。
gitCommitMsg.js const { execFile } = require('child_process'); const fs = require('fs'); const path = require('path'); const formatOptions = ['log', '--pretty=format:%ad %cn committed %s %h', '--date=format:%Y-%m-%d']; const writeStream = fs.createWriteStream(path.join(process.cwd(), 'CHANGELOG.md')); const child = execFile('git', formatOptions, { cwd: process.cwd(), maxBuffer: Infinity, }); child.stdout .pipe(writeStream);复制代码
编译和打包
在项目开发的时候都是通过npm去安装第三方包到本地的node_modules里面,而且为了加快项目的构建速度,会忽略对node_modules里面模块的处理,所以这就需要我们在开发npm包的时候提前做好编译打包的工作。
一般来说,用于node环境的包,只要提供符合CMD规范的包即可,但是用于web的包,就需要提供更多的选项。
-
lib:符合commonjs规范的文件,一般放在lib这个文件夹里面,入口是mian
-
es:符合ES module对方的文件,一般放在es这个文件夹里面,入口是module
-
dist:经过压缩的文件,一般是可以通过script标签直接引用的文件
babel VS TypeScript
Babel是JavaScript的一个编译器,用来将ES6的代码转换成ES5的代码,关于babel更多的介绍可以参考之前的文章babel从入门到放弃。
TypeScript是JavaScript的一个超集,支持JavaScript的多有语法和语义,对于一些新的语法也会有及时的跟进,并且在此之上提供了更多额外的特性,比如静态类型和风丰富的语法。TS的代码也可以通过编译转换成正常的JavaScript代码,所有现在也有一种思路是用JavaScript的语法去进行开发,但是用TS的编译器对代码进行转换。
webpack VS rollup
webpack是现在主流的打包工具,有着活跃和庞大的社区支持。rollup号称是下一代打包方案,很多实验性的功能都是它最先实现的,比如scope hoisting 和tree shaking。webpack由于自己实现了一套类似于node的module方案,所以在打包文件的大小上以及文件的可读性上都存在一定的问题,而且相比于webpack复杂的配置文件,rollup的配置相来说更简单。所以库文件的打包比较好的方案是rollup + babel。
持续迭代
在一般的迭代过程中,步骤可能是
-
修改完本地代码以后,提交这次的修改,运行git add . && git commit && git push
-
修改package.json中的version字段,实现版本号的自增
-
运行git add . && git commit && git push
-
给这个版本打一个tag,git tag <package.version> && git push --tags
-
发布到npm,运行npm publish
npm version
npm version用来自动更新npm包的version,对SemVer的版本规范有很好的支持。
npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]
例:初始版本为1.0.0
npm version prepatch
//预备补丁版本号 v1.0.1-0
npm version prerelease
//预发布版本号 v1.0.1-1
npm version patch
//补丁版本号 v1.0.2
npm version preminor
//预备次版本号 v1.1.0-0
npm version minor
//次版本号 v1.1.0
npm version premajor
//预备主版本号 v2.0.0-0
npm version major
//主版本号 v2.0.0
常用的是 major
, minor
和 patch
,分别对应规范中的x,y,z。
当仓库已经被git初始化了,那么运行 npm version
修改完版本号以后,还会运行git add 、git commit和git tag的命令,其中commit的信息默认是自改完的版本号。如果想自定义commit的信息,可以提供 -m 或者 —message 的选项,如果有"%s"的符号,会被替换为版本号。
npm version patch -m "Upgrade to %s for reasons"
npm version还支持pre和post的钩子,可以利用这两个钩子函数做一些自动化的配置。
在preversion这个钩子中,生成changelog文件,并将新生成的文件推入到缓存区中。
在postversion这个钩子中,进行仓库和tag的推送。
简化操作,可以做如下配置
{ "scripts": { "simple": "node gitCommitMsg.js", //生成简单的changelog文件 "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", "preversion": "npm run changelog && git add CHANGELOG.md", "postversion": "git push && git push --tags", "x": "npm version major -m 'Upgrade version to %s '", "y": "npm version minor -m 'Upgrade version to %s '", "z": "npm version patch -m 'Upgrade version to %s '" }, }复制代码
npm publish
和npm version一样,在执行npm publish这个命令的时候,npm会依次执行scripts中的prepublish、publish、postpublish的命令,如果有定义的话。
npm5的版本中,prepublish用来代替prepublishOnly这个钩子,只在publish之前进行调用,建议npm升级到5及以上的版本,保证钩子的一致性。
在包发布之前和之后,我们可以利用prepublish和postpublish这个两个钩子做一些相关的工作。
在开发中,我们都是使用ES6的语法来进行开发的,所以在发布的时候会涉及到代码的编译。一般的开源项目,比如redux、antd,都会提供最少三种的文件格式
1、经过压缩的dist文件,一般放在dist文件夹中,可以用script进行直接引用 2、符合commonjs规范的文件,一般放在lib文件夹中 3、符合ES6模块规范的文件,一般放在es文件夹中 4、符合umd通过规范的文件,在浏览器和node中都可以使用
所以具体的流程为:
-
prepublish,对包进行打包编译
-
publish,只发布编译后的文件
-
postpublish,删除编译生成的文件
"scripts": { "es": "tools run es", "lib": "tools run commonjs", "dist:umd": "tools run dist:umd", "dist:cjs": "tools run dist:cjs", "dist:es": "tools run dist:es", "dist:min": "tools run dist:min", "compile": "npm run es && npm run lib", "dist": "npm run dist:umd && npm run dist:cjs && npm run dist:es && npm run dist:min", "prepublish": "npm run compile && npm run dist", "postpublish": "rm -rf es && rm -rf lib && rm -rf dist", }复制代码
npm tag
使用npm publish发布包的时候,会有一个--tag的选项,如果不提供的话,会默认设置为latest,并且在使用npm install某个包的时候,默认也会安装latest这个tag的包。
但是在进行包的迭代的时候,可能会需要发布不同的版本来做新功能的测试,这时候就需要结合SemVer和--tag来进行相应的处理。
npm publish --tag <tagname>
使用上面的命令,可以发布对应的dist-tag。
如果我们想进行下一个大版本的迭代,并用next的dist-tag来表示
npm publist --tag next
如果用户想安装这个tag下的包,可以使用下面的命令
npm install package@next
可以通过dist-tag来查看某个包的dist-tag
npm dist-tag ls redux latest: 4.0.0 next: 4.0.0-rc.1
当预发版本稳定以后,可以使用 npm dist-tag add beta latest
把预发版本设置为稳定版本。
最终的package#scripts
{ "lint": "eslint --fix src/", "lint:style": "stylelint --fix 'src/**/*.less'", "test": "cross-env BABEL_ENV=test jest --colors --config .jest.js", "pre-commit": "lint-staged", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", "preversion": "npm run changelog && git add CHANGELOG.md", "postversion": "git push && git push --tags", "x": "npm version major -m 'Upgrade version to %s '", "y": "npm version minor -m 'Upgrade version to %s '", "z": "npm version patch -m 'Upgrade version to %s '", "es": "tools run es", "lib": "tools run commonjs", "dist:umd": "tools run dist:umd", "dist:cjs": "tools run dist:cjs", "dist:es": "tools run dist:es", "dist:min": "tools run dist:min", "compile": "npm run es && npm run lib", "dist": "npm run dist:umd && npm run dist:cjs && npm run dist:es && npm run dist:min", "prepublish": "npm run compile && npm run dist" "postpublish": "rm -rf es && rm -rf lib && rm -rf dist", }复制代码
Others
files & .npmignore & .gitignore
有三个方法可以控制npm发布的包中包含哪些文件
-
package.json#files
files字段是一个数组,用来表示可以包含哪些文件,格式和.gitignore的写法一样
-
.npmignore
这个文件用来表示哪些文件将被忽略,格式和.gitignore的写法一样
-
.gitignore
也可以用来表示要忽略哪些文件
这三个的优先级是files > .npmignore > .gitignore
files包含的文件,就算出现在.npmignore和.gitignore,也不会被忽略。如果既没有files字段,也没有.npmignore文件,那么npm会读取.gitignore文件,忽略里面的文件。
main & module & sideEffect
package.json#mai
n 和 package.json#module
这两个字段是用来指定npm包的入口文件,但是两者有一定的不同。
npm在一开始的时候,是node的包管理平台,所有的包都是基于CommonJS 规范规范的,main这个字段是npm自带的,一般表示符合CommonJS规范的文件入口。
rollup实现了基于ES模块静态分析,对代码进行Tree Shaking,它通过识别package.json中的module字段,将它当成是符合ES模块规范的文件入口。webpack之后也进行跟进,也能识别module字段,并且在webpack的默认配置中,module的优先级要高于main,因此符合ES模块规范的代码能进行Tree Shaking,减少项目最终打包出来的代码。
因为一般的项目在配置babel的时候,为了提高构建速度,都会忽略node_modules里面的文件,所以module入口的文件最好是符合ESmodule规范的ES5的代码,webpack最终会把ESmodule转换为它自己的commonjs规范的代码。
package.json#sideEffect
这个字段是webpack4中新增的一个特性,用来表示npm包的代码是否具有副作用。ES6的代码在经过babel编译为ES5的代码后,就算是符合ES6的模块规范,也会出现UglifyJs无法Tree Shaking的问题。webpack4通过sideEffect这个字段,使UglifyJs强行进行Tree Shaking。
sideEffect可以设置为Boolean或者数组
-
当为false时,表明这个包是没有副作用的,可以进行按需引用
-
如果为数组时,数组的每一项表示的是有副作用的文件
在组件库开发的时候,如果有样式文件,需要把样式文件的路径放到sideEffect的数组中,因为UglifyJs只能识别js文件,如果不设置的话,最后打包的时候会把样式文件忽略掉。
{ "sideEffects": ["components/**/*.less"] }复制代码
npm register
npm全局安装后,它的register是registry.npmjs.org ,如果你使用淘宝的镜像重写了register,那么可能会在登陆和发布的时候出错。
npm config list @cfe:registry = " mirrors.npm.private.caocaokeji.cn/repository/… "
registry = " registry.npm.taobao.org/ "
可以使用下面的命令进行登陆和发布
npm login --registryregistry.npmjs.org
npm publish --registryregistry.npmjs.org
或者在开发npm包的时候,将registry换成npm的官方地址,开发完以后再换回淘宝的镜像
npm config set set registrywww.npmjs.com/
npm config set registry registry.npm.taobao.org
npm link
在开发包的时候,会遇到调试问题,希望能够一边开发一边调试,不用频繁的去发布版本。
使用npm link可以达到这个效果,它会在在全局的node_modules目录中生成一个符号链接,指向模块的本地目录。
假设你要开发一个包,叫tool,需要在本地的项目work-center中去使用 在命令行中进入tool的目录,运行npm link这个命令,就会生成一个符号链接。
进入项目work-center的目录,运行npm link tool,就可以使用这个包了。
tool的所有改动都会映射到安装的项目中,但是带来的问题就是一处改动多处影响。
在调试结束后,运行npm unlink tool来删除符号链接。
oh-my-zsh
在Mac上使用oh-my-zsh可以提高命令行的开发效率,具体的配置可以参考这篇文章mac下oh-my-zsh的配置
安装了oh-my-zsh以后,可以简化git的命令行操作,提高键盘的寿命,常用命令如下
zsh-git快捷键 gst - git status gl - git pull gp - git push ga - git add gcmsg - git commit -m gco - git checkout gcm - git checkout master
monorepo & lerna
monorepo 是单代码仓库,与之对应的是multirepo,多代码仓库。
monorepo是把所有的module都放在一个代码仓库中,进行统一管理;multirepo是把module拆分开来,单独去管理。multirepo的问题是issue、changelog和版本号不好管理;monorepo的问题是单个仓库代码量比较大。现在一些主流的开发项目,比如babel、react、vue、vue-cli,都是使用monorepo的方式来管理代码仓库的;rollup和antd是使用multirepo。
lerna是babel官方开源的monorepo管理工具。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 3 分布式 Git - 维护项目
- 开发和维护个人开源项目之徽章收集
- 推荐一些维护大型 Python 项目的工具
- 开发和维护个人开源项目之代码仓库管理
- 安卓维护项目小结以及注意事项[个人总结]
- 选择正确的模型来维护和增强物联网项目
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构与算法分析
Mark Allen Weiss / 冯舜玺 / 电子工业出版社 / 2016-8 / 89.00元
本书是数据结构和算法分析的经典教材,书中使用主流的程序设计语言C++作为具体的实现语言。书中内容包括表、栈、队列、树、散列表、优先队列、排序、不相交集算法、图论算法、算法分析、算法设计、摊还分析、查找树算法、k-d树和配对堆等。本书把算法分析与C++程序的开发有机地结合起来,深入分析每种算法,内容全面、缜密严格,并细致讲解精心构造程序的方法。一起来看看 《数据结构与算法分析》 这本书的介绍吧!