如何为package.json添加注释以进行npm install?

How do I add comments to package.json for npm install?

我有一个简单的package.json文件,我想添加一个注释。有什么方法可以做到这一点吗,或者有什么黑客可以做到这一点吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
{
 "name":"My Project",
 "version":"0.0.1",
 "private": true,
 "dependencies": {
   "express":"3.x",
   "mongoose":"3.x"
  },
 "devDependencies" :  {
   "should":"*"
    /*"mocha":"*" not needed as should be globally installed */
  }
}

上面的示例注释在NPM中断时不起作用。我还尝试了//风格评论。


这一点最近在node.js邮件列表中进行了讨论。

根据创建NPM的Isaac Schlueter的说法:

... the"//" key will never be used by npm for any purpose, and is reserved for comments ... If you want to use a multiple line comment, you can use either an array, or multiple"//" keys.

使用常用工具(NPM、纱线等)时,多个"/"键将被移除。幸存下来:

1
2
3
{"//": [
 "first line",
 "second line" ] }

这将不复存在:

1
2
{"//":"this is the first line of a comment",
 "//":"this is the second line of the comment" }


这是另一个在JSON中添加注释的方法。因为:

1
{"a": 1,"a": 2}

等于

1
{"a": 2}

你可以这样做:

1
2
3
4
5
6
{
 "devDependencies":"'mocha' not needed as should be globally installed",
 "devDependencies" :  {
   "should":"*"
  }
}


在花了一个小时的时间在复杂和黑客的解决方案上之后,我发现自己是一个非常简单、优雅和有效的解决方案,可以用来评论我在package.json中庞大的依赖项部分。就像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
 "name":"package name",
 "version":"1.0",
 "description":"package description",
 "scripts": {
   "start":"npm install && node server.js"
  },
 "scriptsComments": {
   "start":"Runs development build on a local server configured by server.js"
  },
 "dependencies": {
   "ajv":"^5.2.2"
  },
 "dependenciesComments": {
   "ajv":"JSON-Schema Validator for validation of API data"
  }
}

当以同样的方式排序时,我现在很容易在Git提交差异或编辑器中跟踪这些依赖项/注释对,同时使用package.json

而且不需要额外的工具,只需要简单有效的JSON。

希望这对任何人都有帮助。


您可以滥用重复的密钥被覆盖的事实。这就是我刚才写的:

1
2
3
4
5
6
7
8
9
10
"dependencies": {
 "grunt":"...",
 "grunt-cli":"...",

 "api-easy":"# Here is the pull request: https://github.com/...",
 "api-easy":"git://..."

 "grunt-vows":"...",
 "vows":"..."
}

但是,尚不清楚JSON是否允许重复的键(请参见JSON语法允许对象中有重复的键吗?它似乎与新产品经理合作,所以我承担风险。

建议的黑客程序是使用"//"密钥(来自nodejs邮件列表)。但是,当我测试它时,它不适用于"依赖性"部分。另外,本文中的示例使用多个"//"键,这意味着NPM不会拒绝具有重复键的JSON文件。换言之,上面的黑客应该永远是好的。

更新:重复密钥攻击的一个令人恼火的缺点是,npm install --save悄悄地消除了所有重复项。不幸的是,它很容易被忽视,你善意的评论也消失了。

"//"黑客仍然是最安全的。但是,npm install --save也将删除多行注释。


NPS(节点包脚本)为我解决了这个问题。允许您将NPM脚本放入单独的JS文件中,在该文件中可以添加大量注释和需要的任何其他JS逻辑。网址:https://www.npmjs.com/package/nps

我的一个项目的package-scripts.js样本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
  scripts: {
    // makes sure e2e webdrivers are up to date
    postinstall: 'nps webdriver-update',

    // run the webpack dev server and open it in browser on port 7000
    server: 'webpack-dev-server --inline --progress --port 7000 --open',

    // start webpack dev server with full reload on each change
    default: 'nps server',

    // start webpack dev server with hot module replacement
    hmr: 'nps server -- --hot',

    // generates icon font via a gulp task
    iconFont: 'gulp default --gulpfile src/deps/build-scripts/gulp-icon-font.js',

    // No longer used
    // copyFonts: 'copyfiles -f src/app/glb/font/webfonts/**/* dist/1-0-0/font'
  }
}

我刚在本地安装了npm install nps -save-dev,并将其放入我的package.json脚本中。

1
2
3
4
"scripts": {
   "start":"nps",
   "test":"nps test"
}

我有一个有趣的想法。

为package.json中的dependenciesdevDependencies块适当地创建npm包名称作为注释分隔符,例如x----x----x

1
2
3
4
5
6
7
8
9
10
11
12
{
   "name":"app-name",
   "dependencies": {
       "x----x----x":"this is the first line of a comment",
       "babel-cli":"6.x.x",
       "babel-core":"6.x.x",
       "x----x----x":"this is the second line of a comment",
       "knex":"^0.11.1",
       "mocha":"1.20.1",
       "x----x----x":"*"
    }
}

注意:必须在块中添加最后一个注释分隔符行,其有效版本如*


许多有趣的想法。

我一直在做的是:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
  ...
 "scripts": {
   "about":"echo 'Say something about this project'",
   "about:clean":"echo 'Say something about the clean script'",
   "clean":"do something",
   "about:build":"echo 'Say something about building it'",
   "build":"do something",
   "about:watch":"echo 'Say something about how watch works'",
   "watch":"do something",
  }
  ...
}

这样,我既可以阅读脚本本身中的"伪注释",也可以运行以下类似的操作,以查看终端中的某种帮助:

1
2
npm run about
npm run about:watch

我的讨论内容:)


到目前为止,这里的大多数"黑客"都建议滥用JSON。但是,为什么不滥用底层脚本语言呢?

编辑最初的响应是使用# add comments here将描述放在右边进行包装;但是,这在Windows上不起作用,因为将忽略标志(例如npm run myframework----myframework标志)。我更改了我的响应以使它在所有平台上都能工作,并添加了一些缩进以便于阅读。

1
2
3
4
5
6
7
8
9
10
{
"scripts": {
   "help":"       echo 'Display help information (this screen)';          npm run",
   "myframework":"echo 'Run myframework binary';                          myframework",
   "develop":"    echo 'Run in development mode (with terminal output)';  npm run myframework"
   "start":"      echo 'Start myFramework as a daemon';                   myframework start",
   "stop": "      echo 'Stop the myFramework daemon';                     myframework stop"
   "test":"echo "Error: no test specified" && exit 1"
  }
}

这将:

  • 不要破坏JSON的遵从性(或者至少它不是一个黑客,并且您的IDE不会给您做奇怪的、危险的事情的警告)
  • 跨平台工作(在MacOS和Windows上测试,假设它在Linux上工作正常)
  • 不妨碍运行npm run myframework -- --help
  • 运行npm run时会输出有意义的信息(这是实际运行的命令,用于获取可用脚本的信息)
  • 提供更显式的帮助命令(如果某些开发人员不知道NPM运行会提供此类输出)
  • 将在运行命令本身时同时显示命令及其说明
  • 在打开package.json时(使用less或您最喜欢的IDE)具有一定的可读性。

  • 以下是我对package.jsonbower.json的评论:

    我有一个package.json.js,其中包含一个导出实际package.json的脚本。运行脚本将覆盖旧的package.json,并告诉我它做了哪些更改,这非常好,可以帮助您跟踪npm所做的自动更改。这样我甚至可以通过编程定义我想要使用的包。

    最新的咕噜声任务如下:https://gist.github.com/marzab/72fa6b85bc9e71de5991


    另一个黑客。我创建了一个脚本来读取package.json作为车把模板的上下文。

    如果有人发现这种方法有用,请使用下面的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    const templateData = require('../package.json');
    const Handlebars = require('handlebars');
    const fs = require('fs-extra');
    const outputPath = __dirname + '/../package-json-comments.md';
    const srcTemplatePath = __dirname + '/package-json-comments/package-json-comments.hbs';

    Handlebars.registerHelper('objlist', function() {
      // first arg is object, list is a set of keys for that obj
      const obj = arguments[0];
      const list = Array.prototype.slice.call(arguments, 1).slice(0,-1);

      const mdList = list.map(function(k) {
        return '* ' + k + ': ' + obj[k];
      });

      return new Handlebars.SafeString(mdList.join("
    "));
    });

    fs.readFile(srcTemplatePath, 'utf8', function(err, srcTemplate){
      if (err) throw err;
      const template = Handlebars.compile(srcTemplate);
      const content = template(templateData);

      fs.writeFile(outputPath, content, function(err) {
        if (err) throw err;
      });
    });

    车把模板文件package-json-comments.hbs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    ### Dependency Comments
    For package: {{ name }}: {{version}}

    #### Current Core Packages
    should be safe to update
    {{{objlist dependencies
              "@material-ui/core"
              "@material-ui/icons"
              "@material-ui/styles"
    }}}

    #### Lagging Core Packages
    breaks current code if updated
    {{{objlist dependencies
              "amazon-cognito-identity-js"
    }}}

    #### Major version change
    Not tested yet
    {{{objlist dependencies
              "react-dev-utils"
              "react-redux"
              "react-router"
              "redux-localstorage-simple"

    }}}

    当删除重复的注释键时,运行package.json工具(npm、yarn等),我开始使用哈希版本,它允许更好地读取多行和多个键,如

    1
    2
    3
    4
    5
    "//": {
     "alpaca":"we use the bootstrap version",
     "eonasdan-bootstrap-datetimepicker":"instead of bootstrap-datetimepicker",
     "moment-with-locales":"is part of moment"
    },

    根据我的IDE,它作为根键是"有效的",但在dependencies中,它抱怨需要一个字符串值。


    我最后得到了一个这样的scripts

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     "scripts": {
       "//-1a":"---------------------------------------------------------------",
       "//-1b":"---------------------- from node_modules ----------------------",
       "//-1c":"---------------------------------------------------------------",
       "ng":"ng",
       "prettier":"prettier",
       "tslint":"tslint",
       "//-2a":"---------------------------------------------------------------",
       "//-2b":"--------------------------- backend ---------------------------",
       "//-2c":"---------------------------------------------------------------",
       "back:start":"node backend/index.js",
       "back:start:watch":"nodemon",
       "back:build:prod":"tsc -p backend/tsconfig.json",
       "back:serve:prod":"NODE_ENV=production node backend/dist/main.js",
       "back:lint:check":"tslint -c ./backend/tslint.json './backend/src/**/*.ts'",
       "back:lint:fix":"yarn run back:lint:check --fix",
       "back:check":"yarn run back:lint:check && yarn run back:prettier:check",
       "back:check:fix":"yarn run back:lint:fix; yarn run back:prettier:fix",
       "back:prettier:base-files":"yarn run prettier './backend/**/*.ts'",
       "back:prettier:fix":"yarn run back:prettier:base-files --write",
       "back:prettier:check":"yarn run back:prettier:base-files -l",
       "back:test":"ts-node --project backend/tsconfig.json node_modules/jasmine/bin/jasmine ./backend/**/*spec.ts",
       "back:test:watch":"watch 'yarn run back:test' backend",
       "back:test:coverage":"echo TODO",
       "//-3a":"---------------------------------------------------------------",
       "//-3b":"-------------------------- frontend ---------------------------",
       "//-3c":"---------------------------------------------------------------",
       "front:start":"yarn run ng serve",
       "front:test":"yarn run ng test",
       "front:test:ci":"yarn run front:test --single-run --progress=false",
       "front:e2e":"yarn run ng e2e",
       "front:e2e:ci":"yarn run ng e2e --prod --progress=false",
       "front:build:prod":"yarn run ng build --prod --e=prod --no-sourcemap --build-optimizer",
       "front:lint:check":"yarn run ng lint --type-check",
       "front:lint:fix":"yarn run front:lint:check --fix",
       "front:check":"yarn run front:lint:check && yarn run front:prettier:check",
       "front:check:fix":"yarn run front:lint:fix; yarn run front:prettier:fix",
       "front:prettier:base-files":"yarn run prettier "./frontend/{e2e,src}/**/*.{scss,ts}"",
       "front:prettier:fix":"yarn run front:prettier:base-files --write",
       "front:prettier:check":"yarn run front:prettier:base-files -l",
       "front:postbuild":"gulp compress",
       "//-4a":"---------------------------------------------------------------",
       "//-4b":"--------------------------- cypress ---------------------------",
       "//-4c":"---------------------------------------------------------------",
       "cy:open":"cypress open",
       "cy:headless":"cypress run",
       "cy:prettier:base-files":"yarn run prettier "./cypress/**/*.{js,ts}"",
       "cy:prettier:fix":"yarn run front:prettier:base-files --write",
       "cy:prettier:check":"yarn run front:prettier:base-files -l",
       "//-5a":"---------------------------------------------------------------",
       "//-5b":"--------------------------- common ----------------------------",
       "//-5c":"---------------------------------------------------------------",
       "all:check":"yarn run back:check && yarn run front:check && yarn run cy:prettier:check",
       "all:check:fix":"yarn run back:check:fix && yarn run front:check:fix && yarn run cy:prettier:fix",
       "//-6a":"---------------------------------------------------------------",
       "//-6b":"--------------------------- hooks -----------------------------",
       "//-6c":"---------------------------------------------------------------",
       "precommit":"lint-staged",
       "prepush":"yarn run back:lint:check && yarn run front:lint:check"
      },

    我在这里的目的不是澄清一行,只是在我的脚本之间为后端、前端、所有等等设置一些分隔符。

    我不是1A、1B、1C、2A……的超级粉丝。但是钥匙是不同的,我一点问题也没有。


    正如这个答案所解释的,//键是保留的,因此可以常规地用于注释。//注释的问题是,它不能在dependenciesdevDependencies中作为常规依赖项使用,字符串作为版本约束:

    1
    2
    3
    "dependencies": {
     "//":"comment"
    }

    触发错误,

    npm ERR! code EINVALIDPACKAGENAME

    npm ERR! Invalid package name"//": name can only contain URL-friendly
    characters

    尽管具有非字符串值的键被视为无效的依赖项并被有效地忽略:

    1
    2
    3
    "dependencies": {
     "//": ["comment"]
    }

    依赖项本身可以用同样的方式注释掉:

    1
    2
    3
    "dependencies": {
     "foo": ["*","is not needed now"],
    }

    由于依赖项是在package.json被npm修改时排序的,因此在它引用的依赖项上放置注释是不切实际的:

    1
    2
    3
    4
    5
    "dependencies": {
     "bar":"*",
     "//": ["should be removed in 1.x release"]
     "foo":"*",
    }

    如果注释键引用了特定行,则应相应地命名它,因此它不会被移动:

    1
    2
    3
    4
    5
    "dependencies": {
     "bar":"*",
     "foo":"*",
     "foo //": ["should be removed in 1.x release"]
    }

    适用于特定依赖项的注释可以作为semver的一部分添加:

    1
    2
    3
    4
    "dependencies": {
     "bar":"*",
     "foo":"* || should be removed in 1.x release"
    }

    注意,如果OR前面的第一部分不匹配,则可以分析注释,例如1.x

    这些解决方法与所有当前NPM版本(6及以下)兼容。


    我对JSON中没有任何评论感到沮丧。我创建了新的节点,以它们所引用的节点命名,但前缀是下划线。这是不完美的,但功能性的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    {
     "name":"myapp",
     "version":"0.1.0",
     "private": true,
     "dependencies": {
       "react":"^16.3.2",
       "react-dom":"^16.3.2",
       "react-scripts":"1.1.4"
      },
     "scripts": {
       "__start": [
           "a note about how the start script works"
        ],
       "start":"react-scripts start",
       "build":"react-scripts build",
       "test":"react-scripts test --env=jsdom",
       "eject":"react-scripts eject"
      },
     "__proxy": [
       "A note about how proxy works",
       "multilines are easy enough to add"
      ],
     "proxy":"http://server.whatever.com:8000"
    }