前面学习微应用的知识告一段落,今天学习一下一直一来很疑惑的一件事情,当我想参与若川大佬的源码计划时本想从最简单的omt
源码开始学起,结果开始就是结束,从我想了解的怎么写一套代码可以打包成好几种格式开始就开始卡壳。还好有大佬指路,于是决定看着官网自己重学一下package.json
然后按照配置自己尝试一下写一套代码可以打包成好几种格式的实现。
下面是我对官网上一些字段的翻译,一些常见的可以很直观理解就略过了,大概翻译了下面这些属性:
files
、main
、bin
scripts
workspaces
如果很清楚的可以直接略过中间这部分。
【译】package.json
files
files配置项是一个文件数组,它描述了当你的包被作为依赖安装时所必要的文件。如果配置为空数组,则除了自动排除的文件之外的所有内容都将包含在发布中。 如果你在数组中配置的是一个文件夹,那么它也将包括该文件夹中的文件(除非它们会被本节中的另一个规则忽略) 。
你可以提供一个.npmignore
文件在根目录或者子目录,这将排除这些文件。在你的根包中files属性不能重复,但是在子目录里面可以重复。.npmignore
文件和.gitignore
的功能类似。如果也配置了.gitignore
文件,.npmingore
文件会失效,会被.gitignore
的内容替代掉。
package.json files
中配置的文件不能在 .npmignore
或者 .gitignore
中排除。
已下这些文件总会被包含:
package.json
README
CHANGES
/CHANGELOG
/HISTORY
LICENSE
/LICENCE
NOTICE
The file in the "main" field
README
, CHANGES
, LICENSE
& NOTICE
这些文件可以包含一些案例和扩展等.
Conversely, some files are always ignored:
.git
CVS
.svn
.hg
.lock-wscript
.wafpickle-N
.*.swp
.DS_Store
._*
npm-debug.log
.npmrc
node_modules
config.gypi
*.orig
package-lock.json
(use shrinkwrap instead)
main
main
文件是项目的入口文件。这就是说,如果你的包名命名为foo,如果使用者安装了你的包,使用require(foo)
你的主模块将会被导出。
这应该是一个相对于包文件夹根的模块ID。
This should be a module ID relative to the root of your package folder.
For most modules, it makes the most sense to have a main script and often not much else.
对于大多数模块来说,大多数场景都是只有一个主脚本,而通常没有其他东西。
bin
有许多的包包含一个或多个可执行的文件,这些文件想要安装在path中。npm让这变得简单(事实上,它使用这个特征来安装npm可执行文件)
怎么用,npm在package.json中提供一个bin字段,bin
的配置可以将命令映射到本地的文件名。当包是被全局安装的时候,配置的文件会被连接到全局的bins
文件夹或者将打开一个命令行工具用来执行bin
字段中的配置文件,因此bin
里面的配置可以执行通过name
或者name.cmd
(例如我全局安装了node,如果指定了node,就可以直接在命令行中执行node相关命令)。当这个包被安装为另一个包的依赖项时,该文件将被链接到该包中,可以通过npm exec直接访问,也可以通过npm run-script调用其他脚本时通过名称访问。
To use this, supply a bin
field in your package.json which is a map of command name to local file name. When this package is installed globally, that file will be either linked inside the global bins directory or a cmd (Windows Command File) will be created which executes the specified file in the bin
field, so it is available to run by name
or name.cmd
(on Windows PowerShell). When this package is installed as a dependency in another package, the file will be linked where it will be available to that package either directly by npm exec
or by name in other scripts when invoking them via npm run-script
.
例如:
For example, myapp could have this:
{ "bin" : { "myapp" : "./cli.js" } }
当你安装myapp时,事实上操作系统会从cli.js
创建一个软链接到/usr/local/bin/myapp
如果是windows将会创建一个cmd文件通常位置在C:\Users\{Username}\AppData\Roaming\npm\myapp.cmd
,这个可执行文件会运行cli.js
脚本.
So, when you install myapp, in case of unix-like OS it'll create a symlink from the cli.js
script to /usr/local/bin/myapp
and in case of windows it will create a cmd file usually at C:\Users\{Username}\AppData\Roaming\npm\myapp.cmd
which runs the cli.js
script.
如果你的是一个单一的可执行文件,它的名字必须是和package的包名一致,然后你就可以只提供一个字符串类似下面的例子:
If you have a single executable, and its name should be the name of the package, then you can just supply it as a string. For example:
{ "name": "my-program"
, "version": "1.2.5"
, "bin": "./path/to/program" }
上面配置和下面效果一样:
would be the same as this:
{ "name": "my-program"
, "version": "1.2.5"
, "bin" : { "my-program" : "./path/to/program" } }
请确保在你引用的bin文件以#!/usr/bin/env node
开始,否则脚本将在没有可节点可执行文件的情况下启动!!
Please make sure that your file(s) referenced in bin
starts with #!/usr/bin/env node
, otherwise the scripts are started without the node executable!
scripts
scripts
属性是一个由script命令组成的字典, 它会在包生命周期的不同时间运行。 key是生命周期事件,value是在该节点时运行的命令.
The "scripts" property is a dictionary containing script commands that are run at various times in the lifecycle of your package. The key is the lifecycle event, and the value is the command to run at that point.
See npm-scripts
to find out more about writing package scripts.
workspaces
可选的工作空间字段是一个文件模式的数组集合,它描述了存在于本地文件系统中的位置,安装客户端应该挨个查找工作空间以找到需要符号链接到顶层node_modules
文件夹
The optional workspaces
field is an array of file patterns that describes locations within the local file system that the install client should look up to find each workspace that needs to be symlinked to the top level node_modules
folder.
它既可以描述要用作工作区的文件夹的直接路径,也可以定义解析到这些相同文件夹的glob。
It can describe either the direct paths of the folders to be used as workspaces or it can define globs that will resolve to these same folders.
在下面例子中,文件夹中的所有文件夹./packages
将被视为工作区,只要工作区有有效的package.json
文件
In the following example, all folders located inside the folder ./packages
will be treated as workspaces as long as they have valid package.json
files inside them:
{
"name": "workspace-example",
"workspaces": [
"./packages/*"
]
}
See workspaces
for more examples.
非标准属性
type
阙值modules
和commonjs
,指定使用什么模块,package.json指定"type": "commonjs",
使用import
语法提示报错
index.js
import { add } from "./calc";
const result = add(1, 2);
console.log(result);
calc.js
export const add = (param1, param2) => {
if (typeof param1 !== Number || typeof param2 != Number) return;
return param1 + param2;
};
modules
modules和main的区别可以参考这篇文章
总结:如果我们的package.json
文件同时指定了main
和module
字段
当打包工具遇到我们的模块时
如果它已经支持
pkg.module
字段则会优先使用 ES6 模块规范的版本,这样可以启用 Tree Shaking 机制。如果它还不识别
pkg.module
字段则会使用我们已经编译成 CommonJS 规范的版本,也不会阻碍打包流程。
types
指定使用的ts检验文件路径
husky
代码提交前执行的钩子函数
files
当你的包被作为依赖安装时所必要的文件,是一个数组
browserslist
系统支持的浏览器列表
这些和上面和我想了解的怎么写一套代码可以打包成多种代码格式都没有关系,但是和打包工具扯上关系就有关系了
测试使用的打包工具rollup
我的package.json文件
{
"name": "test-package.json",
"version": "1.0.0",
"description": "",
"main": "index.js",
"module": "./dist/bundle.js",
"type": "module",
"scripts": {
"exec": "node ./index.js",
"build": "rollup index.js --file ./dist/bundle.js --format umd --name 'hello'",
"build:dev": "rollup -c"
},
"bin": "",
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"rollup": "^3.4.0"
}
}
运行npm run build:dev
实际运行的是rollup -c
需要配置rollupl.config.js文件
rollupl.config.js配置 output
为数组即可
const isProd = process.env.NODE_ENV === "production";
export default {
input: "./index.js",
//output可配置为一个数组
output: [
{
file: `./lib/umd/calc${isProd ? "min" : "dev"}.js `,
format: "umd",
name: "calc",
sourceMap: true,
},
{
file: `./lib/system/calc${isProd ? ".min" : ".dev"}.js`,
format: "system",
sourcemap: true,
},
{
file: `./lib/esm/calc${isProd ? ".min" : ".dev"}.js`,
format: "esm",
sourcemap: true,
},
],
};
生成最终的打包好的文件目录结构
这样如果我们在其他项目中需要使用这个包就可以直接引用lib里面的打包好的文件,并且支持多种格式