关于package.json:packagejson配置项记录

main当该我的项目是一个npm包时,main指定的文件,将会被作为包的入口。 // craco-less的package.json{ "main": "./lib/craco-less.js"}// index.jsconst CracoLessPlugin = require('craco-less');下面的require('craco-less')所拜访的就是node_modues/craco-less里的./lib/craco-less.js文件。 module学习中。。。

February 17, 2024 · 1 min · jiezi

关于package.json:浅析-packagejson

每个前端我的项目中都有一个 package.json 文件,你理解它吗?花几分钟再从新扫视一下这个相熟的陌生人。 如何生成 package.json在我的项目文件夹下执行npm init -y疾速生成。 -y代表一路 yes。关上文件咱们看到以下信息。 { "name": "package-json", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC"}一一介绍下上述字段: name包名称,必填项version包版本,必填项description包形容信息,一句话介绍这个包的用处main包入口文件。如require('package-json'),相当于应用了包的index.js。 该字段在开发 npm 包时较为常见,身为切图仔的咱们接触的不多。scripts包执行脚本,罕用的npm start、 npm run dev、 npm run build都是注册在这里的。keywords关键词与 description 相似,用于介绍包的用处author 包创建者license 包协定,用于规定是否开源、是否付费web 我的项目的 package.json大部分开发者是围绕 web 开发进行工作的。咱们来看看 web 我的项目的 package.json 常见配置字段 dependencies、devDependencies、private、scripts... dependencies & devDependencies面试官:请讲讲 dependencies和devDependencies的区别?简略,dependencies是生产环境的依赖,安装包时执行npm install -S xxx;devDependencies 是开发环境的依赖, 安装包须要执行 npm install -D xxx ...

October 2, 2021 · 1 min · jiezi

文件-packagejson-的说明文档

Package.json文档复制 yarnpkg 官方文档,并不是完全复制,增加了一些内容和一些描述,作为笔记存储。你也可以参考 npm documentation, std-pkg, clean-publish, package-json-validator, cosmiconfig, rc。 欢迎 Star: https://github.com/jaywcjlove... 重要字段你的 package.json 中最重要的两个字段是 name 和 version,如果没有它们,您的包将无法安装。 name 和version 字段一起用于创建唯一ID。 name{ "name": "my-awesome-package"}这是您的 包 的名称。 它在URL中使用,作为参数命令行,以及 node_modules 中的目录名。 yarn add [包名]# ornpm install [包名]node_modules/[包名]https://registry.npmjs.org/[包名]/-/[包名]-[version].tgz规则 必须小于或等于214个字符(包括 @scope/ for 范围包)。不能以点(.)或下划线(_)开头。名称中不得包含大写字母。必须仅使用URL安全字符。Tips 不要使用和 Node.js 核心模块相同的名字。不要在名字里包含 js 或者 node 单词。短小精悍,让人看到名字就大概了解包的功能,记住它也会被用在 require() 调用里。保证名字在 npm registry 里是唯一的。version包的当前版本,严格遵循 Semantic Versioning 2.0.0 语义化版本规范。 { "version": "1.0.0"}信息类字段descriptionDescription 是帮助使用者了解包的功能的字符串,包管理器也会把这个字符串作为搜索关键词。 { "description": "我的包的概要简短描述"}keywords关键字是一个字符串数组,当在包管理器里搜索包时很有用。 { "keywords": ["short", "relevant", "keywords", "for", "searching"]}license所有包都应该指定许可证,以便让用户了解他们是在什么授权下使用此包,以及此包还有哪些附加限制。 ...

June 25, 2019 · 3 min · jiezi

vueSSR: 从0到1构建vueSSR项目 --- 伪热更新

伪热更新上一期写了一些问题。原计划是暂时不做处理的,最终结果就是今天没忍住鸭。废话不多说先贴思路1.先进行本地编译2.编译完成后,利用chokidar分别监听源码文件以及编译后的文件。(源码改动,触发编译。编译后的文件发生改动,触发重载)3.开启node服务4.开启browserSync代理服务用到的插件以及模块 npm //执行脚本命令 browser-sync //刷新浏览器的核心 chokidar //监听文件的修改 child_process //开启子进程 执行脚本步骤1直接使用npm对象执行写好的命令function directives(commond,cb){ npm.load(function(){ //清除缓存 npm.commands.cache([‘clean’], function(){ npm.commands.run([commond],cb); }) })}//执行 npm run devfunction dev(cb){ return directives(‘dev’,function(){ cb && cb(); })}步骤2chokidar可以监听文件。具体去看文档嘛chokidar的change事件,只要你进行保存就会触发 不管你有没有发生改变。//监听源码部分//监听源码函数,发生改变 开启子进程 执行编译命令 function soundCode(cb){ console.log(${num+=1}.chokidar开始监听src&public下的文件) const warcher = .watch([‘src//.’,‘public//.’]) warcher.on(‘all’, (event, path) => { if(event ===‘change’){ console.log(’\033[40;31m ‘+path+‘源码发生修改,进行编译,请稍后’); //开启子进程并执行命令 child_process.exec(’npm run dev’,function(error, stdout, stderr){ if (error) { console.log(error.stack); console.log(‘Error code: ‘+error.code); console.log(‘Signal received: ‘+error.signal); } console.log(stdout); console.log(‘编译完成’); }) } }); console.log(’\033[40;32m 源码监听完成’);}// 监听编译后的代码(js)是否发生改变(不如说是进行保存)//监听distDev下的文件 编译后的代码 function compileCompleteCode(cb){ console.log(${num+=1}.chokidar开始监听distDev下的文件); //该文件产生变化时 说明构建已完成。 const watcher = chokidar.watch(‘distDev//*.js’); watcher.on(‘all’, (event, path) => { if(event === ‘change’){ console.log(path+‘发生变化,开始进行热更新’); bs.reload(path); console.log(‘热更新已完成’); } }); console.log(’\033[40;32m 编译后的代码监听完成’);}步骤3 directives(‘devServer’);步骤4 bs.init({ proxy: ‘http://localhost:8080’, open: false });整体代码const npm = require(’npm’);const bs = require(‘browser-sync’).create();const chokidar = require(‘chokidar’);const child_process = require(‘child_process’)var num = 0;//计数function directives(commond,cb){ npm.load(function(){ npm.commands.cache([‘clean’], function(){ npm.commands.run([commond],cb); }) })}function dev(cb){ return directives(‘dev’,function(){ cb && cb(); })}//监听源码函数function soundCode(cb){ console.log(${num+=1}.chokidar开始监听src&public下的文件) const warcher = chokidar.watch([‘src//.’,‘public//.’]) warcher.on(‘all’, (event, path) => { if(event ===‘change’){ console.log(’\033[40;31m ‘+path+‘源码发生修改,进行编译,请稍后’); child_process.exec(’npm run dev’,function(error, stdout, stderr){ if (error) { console.log(error.stack); console.log(‘Error code: ‘+error.code); console.log(‘Signal received: ‘+error.signal); } console.log(stdout); console.log(‘编译完成’); }) } }); console.log(’\033[40;32m 源码监听完成’);}//监听distDev下的文件 编译后的代码function compileCompleteCode(cb){ console.log(${num+=1}.chokidar开始监听distDev下的文件); //该文件产生变化时 说明构建已完成。 const watcher = chokidar.watch(‘distDev//*.js’); watcher.on(‘all’, (event, path) => { if(event === ‘change’){ console.log(path+‘发生变化,开始进行热更新’); bs.reload(path); console.log(‘热更新已完成’); } }); console.log(’\033[40;32m 编译后的代码监听完成’);}console.log(${num+=1}.进行本地编译);dev(function(){ console.log("\033[40;31m 编译完成") soundCode() compileCompleteCode() console.log(${num+=1}开启node服务) directives(‘devServer’); console.log(${num+=1}开启browserSync代理服务); bs.init({ proxy: ‘http://localhost:8080’, open: false });});项目github地址项目公网地址1) vueSSR: 从0到1构建vueSSR项目 — 初始化2) vueSSR: 从0到1构建vueSSR项目 — 路由的构建3) vueSSR: 从0到1构建vueSSR项目 — node以及vue-cli3的配置4) vueSSR: 从0到1构建vueSSR项目 — vuex的配置(数据预取)5) vueSSR: 从0到1构建vueSSR项目 — 开发环境的部署6) vueSSR: 从0到1构建vueSSR项目 — 伪热更新 ...

March 7, 2019 · 2 min · jiezi

BundlePhobia

1、BundlePhobia用于分析npm package的依赖、bundle后的大小、下载速度预估等等,帮助你在引用一个package之前了解引入该package的代价。2、也可以将项目的package.json文件上传,BundlePhobia会帮你评估项目中所有包的大小和加载速度。

February 14, 2019 · 1 min · jiezi

[NodeJs系列]聊一聊 package.json 中的各种 dependency

日常开发中,我们常见到各种dependency,今日得空整理了一下dependency 与 devDependency几乎在每个应用中我们都会见到dependency和devDependency的身影。dependency定义的是代码所需要的依赖包,而devDependency给定的是编译/测试等开发时所需依赖包。举个例子:{ “name”: “project”, “script”: { // 代码打包 “build”: “./node_modules/.bin/webpack …” }, “dependency”: { “react”: “^16.6.3”, … }, “devDependency”: { “webpack”: “4.19.1”, “url-loader”: “1.1.1”, … }}理想情况下,当运行npm run build后应该只包含react相关代码而不包括devDependency中的无用代码。当然,在这里dependency和devDependency只是一个规范,最终生成什么代码取决于你引入了什么,比如improt ‘url-loader’会把url-loader囊括进你的生产代码,不论它是否定义在dependency中。现在考虑另外一个场景,我们开发了一个npm(package-a)包,我们希望所有依赖package-a的应用都能有效的运行。这时dependency和devDependency并不仅仅是一个我们可以随意遵守的规范而已,因为项目依赖的devDependency 不会被安装。比如:├── project ├── package-a (dependency) │ └── package-a-1 (devDependency) └── package-b (devDependency)在project下执行npm install之后,package-a和package-b 都会被安装,但package-a-1不会被安装,所以你在project的 node_modules文件夹下找不到package-c。综上所述,在开发一个应用时,我们应该把生产需要的依赖放在dependency中,把单元测试/编译/打包等这些生产无关依赖放在devDependency中peerDependencies我们以babel-loader为例子,运行npm install babel-loader -D时,控制台会有两条警告:npm WARN babel-loader@8.0.4 requires a peer of @babel/core@^7.0.0 but none is installed. You must install peer dependencies yourself.npm WARN babel-loader@8.0.4 requires a peer of webpack@>=2 but none is installed. You must install peer dependencies yourself.提示babel-loader需要依赖@babel/core@^7.0.0和webpack@>=2。这是因为peerDependencies指定了当前包需要安装的依赖:“peerDependencies”: { “@babel/core”: “^7.0.0”, “webpack”: “>=2” }那应该在什么情况下使用呢?一般的,如果我们需要开发针对于某个库的插件而又不需要在代码中引用这个库的时候。就比如babel-loader是webpack的一个插件,但代码中又无需引用webpack,为了保证插件能够运行在webpack环境中,故而使用了peerDependencies。bundledDependencies又可称为:bundleDependencies再以一个例子阐述:{ “name”: “project”, “dependencies”: { “react”: “^16.6.3”, “react-dom”: “^16.6.3” }, “bundleDependencies”: [ “react”, “react-dom” ], “version”: “1.0.0”}当我们需要使用npm pack打包这个应用时,其最终生成的文件结构如下:project-1.0.0.tgz ├── node_modules | └── react | └── react-dom └── package.json如果不使用bundleDependencies,文件结构如下:project-1.0.0.tgz ├── project-1.0.0.tgz | └── node_modules | └── react | └── react-dom └── package.jsonso,bundleDependencies的作用是将指定依赖归置于当前项目下,这样你就可以快速的运行你pack后的项目。optionalDependencies如果你的应用中依赖了optional-a,而这个依赖又是可有可无的,也就是说如果optional-a找不到或者安装失败,你希望程序依旧运行。这时候optionalDependencies就能很好的满足你的要求。注意:optionalDependencies会覆盖dependencies中的同名包try { let optionalA = require(‘optional-a’);} catch (er) { optionalA = null}参考What’s the difference between dependencies, devDependencies and peerDependencies in npm package.json file?Peer DependenciesPackage.json ...

December 29, 2018 · 1 min · jiezi

npm关于package.json安装的那些事

前端开发的时候经常用到npm安装依赖包,初步使用的时候会跟着使用很多命令–save -dev之类的,看起来没有太大的区别,那为什么要这么用呢?就要深入了解一下package.json文件。package.json是什么很多时候我们都是站在别人的肩膀上写代码,会引入很多依赖包,那自然,就需要对这些包的安装卸载有一个统一的管理。创建package.json文件是用来管理npm依赖包的最好方式。虽然是这么说,但是很明确,package.json只是一个记录文件,不是管理方式,管理的事还是npm在做。那首先一开始,我们需要生成package.json文件创建package.json文件npm initnpm init –yes生成文件有两个命令,前者是手动命令,输入后,我们可以手动配置项目的一些信息,不输入直接回车,就会自动填充默认配置。后者是快捷命令。顾名思义,快捷命令就是按照默认设置,直接生成文件,文件内容如下:{ “name”: “test”, “version”: “1.0.0”, “description”: “”, “main”: “index.js”, “scripts”: { “test”: “echo "Error: no test specified" && exit 1” }, “keywords”: [], “author”: “”, “license”: “ISC”}根据文件我们可以看到一些基本的内容,默认配置的时候取值如下。name:当前目录名称version:永远是 1.0.0description:来自自述文件的信息或空字符串 ““main:永远是 index.jsscripts:默认情况下会创建一个空test脚本keywords:空的author:空的license: ISCbugs:来自当前目录的信息(如果存在)homepage:来自当前目录的信息(如果存在)对于package.json来说,name与version是必须的,也有一定的要求。“name"全是小写的一个词,没有空格允许破折号和下划线"version"以x.x.x的形式遵循semver规范也可以使用初始命令配置一些选项npm set init.author.email “wombat@npmjs.com"npm set init.author.name “ag_dubs"npm set init.license “MIT"如果文件中中没有描述字段,package.json就会使用README.md或README 的第一行。该描述可帮助人们在搜索npm时找到您的包,因此在package.json中写入自定义描述,可以让人更容易找到包。总的来说:package.json文件列出了项目依赖的所有包允许你使用语义版本控制规则指定项目可以使用的包的版本使您的构建可重现,因此更容易与其他开发人员共享依赖包的管理除了上面介绍的package信息之外,就是我们的核心信息——项目中所使用的所有依赖包。仔细发现的话,我们会在package.json文件中找到两种类型的依赖包列表:“dependencies”:项目在生产环境中需要的包。“devDependencies”:开发和测试中需要的包。例如,下面的项目使用my_dep与生产中的主要版本1匹配的任何版本的软件包,并且需要my_test_framework与主要版本3匹配的任何版本的软件包,但仅用于开发:{ “name”: “my_package”, “version”: “1.0.0”, “dependencies”: { “my_dep”: “^1.0.0” }, “devDependencies” : { “my_test_framework”: “^3.1.0” }}–save和–save-dev安装区别向项目中安装package.json中的依赖包的更简单(也更棒的)方法,是从命令行npm install执行此操作,使用–save或 标记命令–save-dev,具体取决于您希望如何使用该依赖项。一个条目添加到您package.json的dependencies:npm install <package_name> –save一个条目添加到您package.json的devDependencies:npm install <package_name> –save-dev我们在使用 npm install 安装模块的模块的时候 ,一般会使用下面这几种命令形式:npm install moduleName # 安装模块到项目目录下npm install -g moduleName # -g 的意思是将模块安装到全局,具体安装到磁盘哪个位置,要看 npm config prefix 的位置。npm install -save moduleName # -save 的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖。npm install -save-dev moduleName # -save-dev 的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖。那么问题来了,在项目中我们应该使用四个命令中的哪个呢?这个就要视情况而定了。下面对这四个命令进行对比,看完后你就不再这么问了。npm install moduleName 命令安装模块到项目node_modules目录下。不会将模块依赖写入devDependencies或dependencies 节点。运行 npm install 初始化项目时不会下载模块。npm install -g moduleName 命令安装模块到全局,不会在项目node_modules目录中保存模块包。不会将模块依赖写入devDependencies或dependencies 节点。运行 npm install 初始化项目时不会下载模块。npm install -save moduleName 命令安装模块到项目node_modules目录下。会将模块依赖写入dependencies 节点。运行 npm install 初始化项目时,会将模块下载到项目目录下。运行npm install –production或者注明NODE_ENV变量值为production时,会自动下载模块到node_modules目录中。npm install -save-dev moduleName 命令安装模块到项目node_modules目录下。会将模块依赖写入devDependencies 节点。运行 npm install 初始化项目时,会将模块下载到项目目录下。运行npm install –production或者注明NODE_ENV变量值为production时,不会自动下载模块到node_modules目录中。总结devDependencies 节点下的模块是我们在开发时需要用的,比如项目中使用的 gulp ,压缩css、js的模块。这些模块在我们的项目部署后是不需要的,所以我们可以使用 -save-dev 的形式安装。像 express 这些模块是项目运行必备的,应该安装在 dependencies 节点下,所以我们应该使用 -save 的形式安装。管理依赖版本npm使用语义版本控制,或者,正如我们经常提到的那样,SemVer,用于管理软件包版本和范围。如果你的package.json目录中有一个文件并且你运行npm install,npm将查看该文件中列出的依赖项并使用语义版本控制下载最新版本参考原文Working with package.json参考npm install ...

December 28, 2018 · 1 min · jiezi

package.json的所有配置项及其用法,你都熟悉么

写在前面在前端开发中,npm已经是必不可少的工具了。使用npm,不可避免的就要和package.json打交道。平时package.json用得挺多,但是没有认真看过官方文档。本文结合npm官方文档以及自己平时使用过程中的感悟,谈一谈package.json。官方文档在这里。初始化使用npm init命令就可以初始化一个package.json文件。在初始化的过程中,会叫用户输入name, version等等信息,当然,你都可以忽略。一路点回车,就生成了下面这样一个初始化的package.json。{ “name”: “test”, // 假如项目叫做test “version”: “1.0.0”, “description”: “”, “main”: “index.js”, “scripts”: { “test”: “echo "Error: no test specified" && exit 1” }, “author”: “”, “license”: “ISC”}上面的package.json包含了项目的名称,版本号,描述,入口文件,执行脚本,作者,开源协议等。package.json的内容远不止这些,下面将一一进行介绍。在开发业务项目和开发组件库的时候,package.json是略有不一样的。我会把我认为重要的配置项加黑标识出来。详细介绍name: 这个很好理解,就是package的名称。不过需要注意的是,name有长度限制(虽然一般都不会超),而且name不能以 【点】 或者 【下划线】开头,name中不能有大写字母。这个是每一个package必须的。在业务代码中,通过require(${name})就可以引入对应的程序包了。version: package的版本。对于业务项目来说,这个往往不太重要,但是如果你要发布自己的项目,这个就显得十分重要了。name和version共同决定了唯一一份代码。npm是用[npm-semver来解析版本号的。我们一般见到的都是大版本.次要版本.小版本这种版本号,比如16.1.0。版本号的规则、含义其实蛮多的,可以参考这篇文章。desription:包的描述。开发组件库时必需,简明的向库的使用者介绍这个库是干嘛的。对于公司的业务项目,这个配置项一般无所谓。keywords:关键词。一个字符串数组,对这个npm包的介绍。组件库必需,便于使用者在npm中搜索。对于公司业务项目,这个配置一般无所谓。homepage: 项目主页。对于开发组件库来说挺有用的。bugs:开发者的联系方式,代码库的issues地址等。如果代码使用者发现了bug,可以通过这个配置项找到提bug的地方。license:开源协议。对于开源组件库,这个十分重要。之前react还因为这事儿没少被社区嫌弃。开源协议略微复杂,用阮一峰前辈的一张图来说明一下吧。注:图里少了ISC, ISC和BSD差不多author:项目的作者。可以为字符串,对象。contributors:项目的贡献者。author的数组。main:代码入口。这个十分重要,特别是对于组件库。当你想在node_modules中修改你使用的某个组件库的代码时,首先在node_modules中找到这个组件库,第一眼就是要看这个main,找到组件库的入口文件。在这个入口文件中再去修改代码吧。scripts:指定了运行脚本命令的npm命令行缩写。十分重要。来看一个例子:“scripts”: { “dev”: “NODE_ENV=dev webpack-dev-server –progress –hot –host 0.0.0.0 –port 8089”, “test”: “NODE_ENV=test webpack –config webpack.test.config.js –progress”, “online”: “NODE_ENV=production webpack –config webpack.online.config.js –progress”, “build”: “webpack”, “node”: “node server.js” },在命令行输入:npm run dev , 对应的命令就会被执行。这里有一个地方需要注意,当执行npm run xxx 的时候,node_modules/.bin/目录会在运行时被加入系统的PATH变量。上面的例子,当我们在命令行输入:npm run build时,其实真正执行的命令是node_modules/.bin/webpack而不是webpack。所以,当你的webpack并未全局安装时,直接在命令行输入:webpack是会报错的。因为你的webapck是安装在node_modules/.bin/下面的。directories:对整个代码结构的描述。告诉代码包使用者可以在哪里找到对应的文件。files:数组。表示代码包下载安装完成时包括的所有文件。repository:对于组件库很有用。让组件库使用者找到你的代码库地址。这个配置项会直接在组件库的npm首页生效。例子:“repository”: { “type”: “git”, “url”: “git+https://github.com/CoyPan/react-scroll-to-show-cb.git”},config:用于添加命令行的环境变量。具体用法见这里。dependencies:项目的依赖。注意,不要把测试工具、代码转换器或者打包工具等放在这里。例如:当你在命令行里面使用npm install react –save时,react就会出现在dependencies。默认是安装最新的版本。如果想安装某个特定的版本,可以npm install react@15.6.2。以下的dependencies,格式都是合法的,“dependencies” : { “foo” : “1.0.0 - 2.9999.9999”, “bar” : “>=1.0.2 <2.1.2”, “baz” : “>1.0.2 <=2.3.4”, “boo” : “2.0.1”, “qux” : “<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0”, “asd” : “http://asdf.com/asdf.tar.gz”, “til” : “~1.2”, “elf” : “~1.2.3”, “two” : “2.x”, “thr” : “3.3.x”, “lat” : “latest”, “dyl” : “file:../dyl” }我们常见的是下面这些:“dependencies”: { “foo”: “1.0.0”, // 指定了就是1.0.0版本 “bar”: “1.2.2”, // 安装版本号不低于1.2.2的1.2.x的最新版本,例如:1.2.3, 1.2.4等等。1.2.1 ,1.3.x 等就不行了 “baz”: “1.2.2”, // 安装版本号不低于1.2.2的1.x.x的最新版本,例如: 1.2.7,1.3.1,1.7.8等。1.2.1 ,2.0.0 等就不行了。注意,如果配置是^0.x.x,则和0.x.x的效果一样。 “lat”: “latest” // 安装最新版本}dependencies 还可以像下面这样配置:“dependencies”: { “foo”: “git+ssh://git@github.com:foo/foo.git#v1.0.1”,}foo组件的地址为git+ssh://{foo代码库的ssh地址}#v{foo的版本号}这样的配置在下面这种场景十分有用:组内的许多项目都有同一个功能,把这个功能抽出来做成组件是很自然的想法。但是每个项目都有自己的代码库,公司也没有内部的npm库,组件应该放在哪里呢?可以专门为组件新建一个代码仓库,将组件放在这里开发、迭代。这样,各个项目都可以引用该组件:只需要在dependencies中将组件配置成上述的形式。至于组件的版本,可以通过git tag来控制。dependencies还有其他的配置方式,具体在这里查看。devDependencies:项目的依赖。主要是在开发过程中依赖的一些工具。用法与dependencies相似。bundledDependencies:数组,打包时的依赖。如果配置了bundledDependencies,在项目中执行 npm pack将项目打包时,最后生成的.tgz包中,会包含bundledDependencies中配置的依赖。bundledDependencies中的依赖必须在devDependencies或者dependencies中声明过。peerDependencies: 指定当前组件的依赖以其版本。如果组件使用者在项目中安装了其他版本的同一依赖,会提示报错。engines:指定项目所依赖的node环境、npm版本等。private:如果设为true,无法通过npm publish发布代码。bin:用来指定各个内部命令对应的可执行文件的路径。具体用法这里不多讲了。详情可以点击这里。总结本文涵盖了package.json绝大部分的配置项。我的观点是:如果是公司的业务项目,对于package.json,一般情况下,我觉得只需要关注好scripts,dependencies,devDependencies这三个地方就够了。而对于开源的组件库,则至少需要关注好上面标黑的几个点。理解好重要配置的含义,提升开发效率,减少踩坑的概率。写在后面本文结合官方文档以及自己平时工作中的体会,阐述了package.json这个配置文件中各项的含义以及用法。符合预期。欢迎关注我的公众号,这里只有干货,符合你的预期。 ...

December 25, 2018 · 1 min · jiezi

npm发布包教程(五):废弃/删除

npm包发布后可以对包进行废弃或删除操作,废弃和删除的区别在于:废弃不会将包或版本从npm仓库删除,仍然可以继续下载安装,并在安装的时候会有警示删除会将包从npm彻底删除,无法被下载安装无论是废弃还是删除,都包含两个层面:版本的废弃/删除包的废弃/删除一、废弃废弃原因:版本:鼓励用户更新最新版本包:此包不再有维护的价值第一步:废弃指定版本语法:npm deprecate <pkg>[@<version>] <message>我们以yuyy-test-pkg为例:npm deprecated yuyy-test-pkg@1.1.0 ’test deprecate’执行后我们用npm view yuyy-test-pkg versions查看版本:记录的版本号并无变化。第二步:安装废弃版本切换到test-my-pkg目录下,执行:npm i yuyy-test-pkg@1.1.0运行结果: 第三步:运行index.js在test-my-pkg目录下node index.js结果:废弃的包除了安装时会有警示,并不影响使用。二、删除npm不鼓励任何形式的删除,主要因为我们发布的包可能已经被其他人引用,如果我们删除了此包,其他人在重新安装含有我们包的依赖的工程时,出现找不到包问题。基于此,npm做了相关的删除限制:删除的版本24小时后方可重发!包发布72小时之内才可删除!第一步:删除发布的包我们之前在《npm发布包教程(二):发布包》发布的包仅为演示所用,为保持npm仓库的纯净,我们都删除掉:npm unpublish yuyy-test-pkg –forcenpm unpublish @yuyy/babel –force第二步:去官网查找第二步切换到test-my-pkg目录下,先将两个包卸载:npm rm yuyy-test-pkg @yuyy/babel结果:然后再重新安装:npm i yuyy-test-pkg @yuyy/babel结果:已经删除的包无法再安装。至此,我们完成npm包的整个生命周期的演示过程,大家可以开源的道路上又多了一条很重要的道路。不过,我觉得作为一个开发者,我们有责任和义务维护每一个社区的纯净,所以在发布npm包的时候应该尽量精益求精。相关文章:1.《npm发布包教程(一):从npm说起》2.《npm发布包教程(二):发布包》3.《npm发布包教程(三):安装发布包》4.《npm发布包教程(四):迭代》5.《npm发布包教程(五):废弃/删除》

December 22, 2018 · 1 min · jiezi

npm发布包教程(四):迭代

一个npm包发布之后,我们难免会修改一些bug,或者增改一些功能,这就涉及到对npm包的迭代。本篇文章就npm迭代涉及到一些知识点进行介绍。本次演示以《npm发布包教程(二):发布包》中发布的包为基础。npm包的每次迭代都要涉及到两个方面:内容的变更版本的变更我们首先来演示内容的变更,以yuyy-test-pkg为例一、更新内容index.js变更为:module.exports = { printMsg: function () { console.log(’this message is from yuyy-test-pkg!’); console.log(’the version of this package has updated!’); }}二、更新版本在演示版本变更前,我们先来了解一下npm版本相关的知识。npm采用语义化版本,共三位,以’.’隔开,从左至右依次代表:主版本(major)、次要版本(minor)、补丁版本(patch)。例如:1.0.0major.minor.patch关于版本变更规范:变更版本号的命令:npm version <major | minor | patch>假如我们本次是次要发布,我们执行命令:npm version minor执行结果:package.json中的version也已变为1.1.0:{ “name”: “yuyy-test-pkg”, “version”: “1.1.0”, “description”: “my first npm package”, “main”: “index.js”, “scripts”: { “test”: “echo "Error: no test specified" && exit 1” }, “keywords”: [ “npm”, “packge” ], “author”: “yuyy”, “license”: “ISC”}三、发布npm publish结果:我们可以通过命令查看我们包的所有版本:npm view yuyy-test-pkg versions结果:四、安装更新(1)切换到test-my-pkg目录下npm up yuyy-pkg结果:(2)执行index.js node index.js输出结果:以上就是npm包迭代的过程,我们本次已unscoped包yuyy-test-pkg为例,对于scoped包的迭代过程没有差异。在下一篇文章《npm发布包教程(四):删除/废弃》中我们将演示npm的废弃和删除。

December 21, 2018 · 1 min · jiezi

npm发布包教程(三):安装发布包

我们在上一篇《npm发布包教程(二):发布包》中演示了如何发布npm包,npm仓库有了我们自己的包,接下来就进入到安装并使用我们自己的包的环节。第一步:初始化测试工程mkdir test-my-pkg && cd test-my-pkg npm init -y第二步:npm官网找包官网输入我们已经发布的包yuyy-test-pkg@yuyy/babel页面会有安装命令,如下图所示:第三步:安装依次执行下面的命令 npm i yuyy-test-pkg npm i @yuyy/babel此时的目录结构:test-my-pkg├── node_modules│ ├── @yuyy│ │ └── babel│ │ ├── README.md│ │ ├── index.js│ │ └── package.json│ └── yuyy-test-pkg│ ├── README.md│ ├── index.js│ └── package.json├── package-lock.json└── package.json第四步:使用(1) 建index.js index.js:let printer = require(‘yuyy-test-pkg’);let otherPrinter = require(’@yuyy/babel’);printer.printMsg();otherPrinter.printMsg();(2) 运行index.jsnode index.js执行结果:this message is from yuyy-test-pkg!this message is from @yuyy/babel!以上即为对我们自己的包引用的整个过程,值得注意的是:我们知道在Node环境中是通过CommonJS的风格管理模块的,所以在第四步引用模块的时候使用的是require()。关于require()的原理,阮一峰老师的《require()源码解读》中有详细介绍,不再赘述,仅将require()的内部原理摘抄整理如下,以伪代码的形式呈现:Node中执行:require(X)解析过程:if(X 是Node内部模块){ return X}else if(X 带路径,以 ‘/‘、‘./‘、’../‘开头){ resolveModule(X)}else if(X 不带路径){ /当前工程/node_modules 执行 resolveModule(X) ./当前工程 node_modules 执行 resolveModule(X) ../当前工程 node_modules 执行 resolveModule(X) . . .}else { return ’not found’}function resolveModule(X){ absolutePath = X的绝对路径(根据X所在的父模块可知) if(X 是文件){ return absolutePath/X || absolutePath/X.js || absolutePath/X.json || absolutePath/X.node; }else if(X 是目录){ return absolutePath/X/package.json(main字段) || absolutePath/X/index.js || absolutePath/X/index.json || absolutePath/X/index.node }}我们将在下一篇文章《npm发布包教程(三):npm包迭代》中演示对已经发布过的包如何进行迭代,包括内容的迭代和版本的迭代。 ...

December 21, 2018 · 1 min · jiezi

npm发布包教程(二):发布包

上一篇文章《npm发布包教程(一):从npm说起》中我们介绍了npm相关的一些知识,旨在让大家对npm有一些深入的理解,这一篇我们正式开始演示发布过程。一、准备工作在正式开始演示前,我们还需要做两项准备工作:1.注册npm账户注册地址全名:邮箱:用户名:重要!发布scoped包时会用到密码:2.全局安装nrmnpm i nrm -gnrm是npm仓库管理的软件,可用于npm仓库的快速切换nrm 常用命令: nrm //展示nrm可用命令 nrm ls //列出已经配置的所有仓库 nrm test //测试所有仓库的响应时间 nrm add <registry> <url> //新增仓库 nrm use <registry> //切换仓库二、发布包开始演示前做两个简短说明:(1)npm官方建议规范的包至少包含:package.json(包的基本信息)README.md(文档)index.js (入口文件)后续的演示都遵循此规范。(2)本次仅演示个人账户的包发布,包括一个unscoped包和一个scoped的包。团体账户下的包发布流程和个人账户差别不大,在此不做展开。1.发布unscoped包yuyy-test-pkg第一步:创建项目(1)创建工程文件夹mkdir yuyy-test-pkg && cd yuyy-test-pkg(2)创建package.json npm init按照提示一步步完善即可,注意:本次演示的包的入口文件是index.js,请务必确保package.json中字段main对应的值是“index.js”。最终结果:{ “name”: “yuyy-test-pkg”, “version”: “1.0.0”, “description”: “my first npm package”, “main”: “index.js”, “scripts”: { “test”: “echo "Error: no test specified" && exit 1” }, “keywords”: [ “npm”, “packge” ], “author”: “yuyy”, “license”: “ISC”}(3)创建README.md内容:### yuyy-test-pkgThis is my first npm package!It is just for learning.(4)创建index.js内容:module.exports = { printMsg: function () { console.log(’this message is from yuyy-test-pkg!’); }}最终的目录结构:└── yuyy-test-pkg ├── README.md ├── index.js └── package.json第二步:发布npm publish可能报的错:(1)未登录npm ERR! code ENEEDAUTHnpm ERR! need auth auth required for publishingnpm ERR! need auth You need to authorize this machine using npm adduser解决办法:npm adduser输入:用户名(忘记的话,去npm网站查看:头像 > Profile Settings)密码邮箱(2)仓库地址不对npm ERR! code E409npm ERR! Registry returned 409 for PUT on http://r.cnpmjs.org/-/user/or...:yuyy: conflict原因:通过nrm ls 命令查看我此时的仓库地址为cnpm,而不是npm解决办法:用nrm切换到npm仓库,执行命令nrm use npm以上问题解决后再次执行发布命令npm publish,发布成功.第三步:去npm 官网搜索有可能有延迟,不能立马看不到。2.发布scoped包@yuyy/babel第一步:创建项目(1)创建工程文件夹mkdir babel && cd babel(2)创建package.json npm init按提示操作,最终结果:{ “name”: “babel”, “version”: “1.0.0”, “description”: “my scoped test package”, “main”: “index.js”, “scripts”: { “test”: “echo "Error: no test specified" && exit 1” }, “keywords”: [ “npm”, “package” ], “author”: “yuyy”, “license”: “ISC”}(3)创建README.md内容:### @yuyy/babelThis is my scoped npm package!It is just for learn.(4)创建index.js内容:module.exports = { printMsg: function () { console.log(’this message is from @yuyy/babel!’); }}最终的目录结构:└── babel ├── README.md ├── index.js └── package.json第二步:发布npm publish报错:没有发布权限npm ERR! publish Failed PUT 401npm ERR! code E401npm ERR! This package requires that publishers enable TFA and provide an OTP to publish. For more info, visit: https://go.npm.me/2fa-guide : babel原因:已经存在babel包,而我又不是babel的发布者解决:包名和域名差不多,先到先得,如果我非要发布一个叫babel的包,只能给它加作用域放到我的命名空间下第三步:加作用域npm init –scope=@yuyy -y@符号后面的是你注册npm账户时的username,如果不记得可以通过npm whoami查询。上面的命令其实是在重新生成package.json,只是会给包增加了作用域,执行完后package.json现在的内容:{ “name”: “@yuyy/babel”, “version”: “1.0.0”, “description”: “my scoped test package”, “main”: “index.js”, “scripts”: { “test”: “echo "Error: no test specified" && exit 1” }, “keywords”: [ “npm”, “package” ], “author”: “yuyy”, “license”: “ISC”}唯一的变化是name字段由原来的babel变成了@yuyy/babel。第四步:再次发布npm publish报错:npm ERR! publish Failed PUT 402npm ERR! code E402npm ERR! You must sign up for private packages : @yuyy/babel原因:npm publish 命令执行,默认是进行私有发布,参见官网publish命令上一篇文章最后提到过scoped的包私有发布时需要收费解决:如果不想花钱,那只能将包面向公共发布,这也符合npm鼓励开源的精神,这一点和GitHub创建仓库类似。第五步:公共发布npm publish –access public执行结果:值得注意的一点:我们的项目名是babel,最终发布的包名是@yuyy/babel,可见发布的包名可以和项目名不一致,包名取决于package.json中的name字段。第六步:npm官网搜索至此,我们完成了npm包发布的全部过程,一个unscoped包:yuyy-test-pkg,另一个scoped包:@yuyy/babel,也包括过程中可能遇到的问题。发布完我们自己的包之后,我们会在下一篇文章中介绍安装自己的包和涉及到的一些引用模块相关的知识,以及后续文章中介绍如何对发布过的包进行升级和废弃等。 ...

December 20, 2018 · 2 min · jiezi

package-lock.json和yarn.lock的包依赖区别

node包管理包是一段可以复用的代码,这段代码可以从全局注册表下载到开发者的本地环境。每个包可能会,也可能不会依赖于别的包。简单地说,包管理器是一段代码,它可以让你管理依赖(你或者他人写的外部代码),你的项目需要这些依赖来正确运行。为啥我们需要一个包管理工具呢?因为我们在Node.js上开发时,会用到很多别人写的JavaScript代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块C和模块D,npm可以根据依赖关系,把所有依赖的包都下载下来并管理起来。否则,靠我们自己手动管理,肯定既麻烦又容易出错。于是一个集中管理的工具应运而生:大家都把自己开发的模块打包后放到npm官网上,如果要使用,直接通过npm安装就可以直接用,不用管代码存在哪,应该从哪下载。Yarn 是为了弥补npm 的一些缺陷[速度慢,稳定性高]而出现的。”npmnpm 为你和你的团队打开了连接整个 JavaScript 天才世界的一扇大门。它是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,包含超过 600000 个 包(package) (即,代码模块)。来自各大洲的开源软件开发者使用 npm 互相分享和借鉴。包的结构使您能够轻松跟踪依赖项和版本。下面是关于 npm 的快速介绍:npm 由三个独立的部分组成:网站网站 是开发者查找包(package)、设置参数以及管理 npm 使用体验的主要途径。注册表(registry)注册表 是一个巨大的数据库,保存了每个包(package)的信息。命令行工具 (CLI)CLI 通过命令行或终端运行。开发者通过 CLI 与 npm 打交道。yarnYarn发布于2016年10月,并在Github上迅速拥有了2.4万个Star。而npm只有1.2万个star。这个项目由一些高级开发人员维护,包括了Sebastian McKenzie(Babel.js)和Yehuda Katz(Ember.js、Rust、Bundler等)。Yarn一开始的主要目标是解决上一节中描述的由于语义版本控制而导致的npm安装的不确定性问题。虽然可以使用npm shrinkwrap来实现可预测的依赖关系树,但它并不是默认选项,而是取决于所有的开发人员知道并且启用这个选项。Yarn采取了不同的做法。每个yarn安装都会生成一个类似于npm-shrinkwrap.json的yarn.lock文件,而且它是默认创建的。除了常规信息之外,yarn.lock文件还包含要安装的内容的校验和,以确保使用的库的版本相同。yarn的优化主要体现在:速度快 :并行安装:无论 npm 还是 Yarn 在执行包的安装时,都会执行一系列任务。npm 是按照队列执行每个 package,也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。而 Yarn 是同步执行所有任务,提高了性能。离线模式:如果之前已经安装过一个软件包,用Yarn再次安装时之间从缓存中获取,就不用像npm那样再从网络下载了。安装版本统一:为了防止拉取到不同的版本,Yarn 有一个锁定文件 (lock file) 记录了被确切安装上的模块的版本号。每次只要新增了一个模块,Yarn 就会创建(或更新)yarn.lock 这个文件。这么做就保证了,每一次拉取同一个项目依赖时,使用的都是一样的模块版本。更好的语义化: yarn改变了一些npm命令的名称,比如 yarn add/remove,感觉上比 npm 原本的 install/uninstall 要更清晰。node包的安装执行工程自身 preinstall当前 npm 工程如果定义了 preinstall 钩子此时会被执行。确定首层依赖模块首先需要做的是确定工程中的首层依赖,也就是 dependencies 和 devDependencies 属性中直接指定的模块(假设此时没有添加 npm install 参数)。工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm 会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。获取模块获取模块是一个递归的过程,分为以下几步:获取模块信息。在下载一个模块之前,首先要确定其版本,这是因为 package.json 中往往是 semantic version(semver,语义化版本)。此时如果版本描述文件(npm-shrinkwrap.json 或 package-lock.json)中有该模块信息直接拿即可,如果没有则从仓库获取。如 packaeg.json 中某个包的版本是 ^1.1.0,npm 就会去仓库中获取符合 1.x.x 形式的最新版本。获取模块实体。上一步会获取到模块的压缩包地址(resolved 字段),npm 会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。查找该模块依赖,如果有依赖则回到第1步,如果没有则停止。模块扁平化(dedupe)上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如 A 模块依赖于 loadsh,B 模块同样依赖于 lodash。在 npm3 以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。yarn和从 npm5 开始默认加入了一个 dedupe 的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是 node-modules 的第一层。当发现有重复模块时,则将其丢弃。这里需要对重复模块进行一个定义,它指的是模块名相同且 semver 兼容。每个 semver 都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在 dedupe 过程中被去掉。安装模块这一步将会更新工程中的node_modules,并执行模块中的生命周期函数(按照 preinstall、install、postinstall 的顺序)。执行工程自身生命周期当前 npm 工程如果定义了钩子此时会被执行(按照 install、postinstall、prepublish、prepare 的顺序)。包依赖关系我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块C和模块D,npm可以根据依赖关系,把所有依赖的包都下载下来并管理起来,而这种依赖又有不一样的表现形式。嵌套依赖扁平依赖嵌套依赖假设目前工程依赖 A, B, C 三个库,而他们对某个库 somelib 存在这样的依赖关系:A - somelib 1.4.xB - somelib 1.6.xC - somelib 1.6.x如果要安装 ABC 三个库,那么 somelib 会存在版本冲突。npm5+/yarn 会在实际安装时,给三个库分别下载各自依赖的 somelib 版本。假设 npm 先安装了 A, 由于 A 依赖 somelib 1.4.x 版本,那么 自身依赖先安装1.4.x 。再安装 B, C 时,由于 B, C 依赖的都不是 1.4.x, 于是安装完之后,关系就变成这个样子了:node_modules├── A│ └── node_modules│ └── somelib 1.4.x├── B│ └── node_modules│ └── somelib 1.6.x└── C └── node_modules └── somelib 1.6.x这样就是嵌套依赖。很显然这种方式很大的浪费了磁盘空间。扁平依赖当关联依赖中包括对某个软件包的重复引用,在实际安装时将尽量避免重复的创建。假设目前工程依赖 A, B, C 三个库,而他们对某个库 somelib 存在这样的依赖关系:A - somelib 1.4.xB - somelib 1.6.xC - somelib 1.6.x如果要安装 ABC 三个库,那么 somelib 会存在版本冲突。npm5+/yarn 会在实际安装时,给三个库分别下载各自依赖的 somelib 版本。假设 npm 先安装了 A, 由于 A 依赖 somelib 1.4.x 版本,那么 1.4.x 会变成主版本。再安装 B, C 时,由于 B, C 依赖的都不是 1.4.x, 于是安装完之后,关系就变成这个样子了:node_modules├── A├── somelib 1.4.x├── B│ └── node_modules│ └── somelib 1.6.x└── C └── node_modules └── somelib 1.6.x这样就是扁平依赖。需要注意的是,明明 B, C 都依赖 1.6.x 版本,实际上 npm5+/yarn 却要把这个版本保存两次,这样明显是对磁盘空间的浪费。我们把这种情况就称为不完全扁平的。目前这种情况还无法安全解决。lock文件锁文件是由包管理器自动生成的。它包含了重现全部的依赖源码树需要的所有信息、你的项目依赖中的所有信息,以及它们各自的版本。现在值得强调的是,Yarn 使用了锁文件,而 npm5以前没有默认锁文件,npm5之后加入了默认锁文件功能。我们会谈到这种差别导致的一些后果。既然我已经向你介绍了包管理器这部分,现在我们来讨论依赖本身。目前常见的两种lock文件:packahe-lock.json 是npm5之后默认生成的锁文件yarn.lock 是yarn的锁文件packahe-lock.json解析{ “name”: “package-name”, “version”: “1.0.0”, “lockfileVersion”: 1, “dependencies”: { “cacache”: { “version”: “9.2.6”, “resolved”: “https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz", “integrity”: “sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==” }, “duplexify”: { “version”: “3.5.0”, “resolved”: “https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz", “integrity”: “sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=”, “dependencies”: { “end-of-stream”: { “version”: “1.0.0”, “resolved”: “https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", “integrity”: “sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=” }, } }}可以看出来,package-lock.json把所有的包的依赖顺序列出来,第一次出现的包名会提升到顶层,后面重复出现的将会放入被依赖包的node_modules当中。引起不完全扁平化问题。yarn.lock解析# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.# yarn lockfile v1package-1@^1.0.0: version “1.0.3” resolved “https://registry.npmjs.org/package-1/-/package-1-1.0.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"package-2@^2.0.0: version “2.0.1” resolved “https://registry.npmjs.org/package-2/-/package-2-2.0.1.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" dependencies: package-4 “^4.0.0"package-3@^3.0.0: version “3.1.9” resolved “https://registry.npmjs.org/package-3/-/package-3-3.1.9.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" dependencies: package-4 “^4.5.0"package-4@^4.0.0, package-4@^4.5.0: version “4.6.3” resolved “https://registry.npmjs.org/package-4/-/package-4-2.6.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"显然yarn.lock锁文件把所有的依赖包都扁平化的展示了出来,对于同名包但是semver不兼容的作为不同的字段放在了yarn.lock的同一级结构中。验证实例在一个测试package工程里面,安装了以下三个包,安装了react-router 3.2.1,另外安装了react-router-dom 4.3.1 和react-router-native 4.3.0,这两个都依赖"react-router”: “^4.3.0”,结果如下:.└── node_modules├── react-router-dom4.3.1│ └── react-router4.3.1├── react-router-native4.3.0│ └── react-router4.3.1└── react-router3.2.1查看package-lock.json结果和最后node_modules安装结果:查看yarn.lock结果和最后node_modules安装结果:lock官方介绍理解 NPM 5 中的 lock 文件知乎问答1知乎问答2 ...

November 20, 2018 · 2 min · jiezi