如何 npm 发布特定的文件夹,但包根

我有一个项目,其中包括一个吞咽任务,用于构建和打包源代码,并将其发布在一个名为 dist的目录中。我的目标是将它作为 npm 包发布,但只发布 dist 文件夹。Npm 文档说我可以使用 files标签来指定要导出的文件。有用。但是,文件也表明:

如果在数组中命名一个文件夹,那么它也将包括这些文件 在那个文件夹里

结果得到一个 npm 包,它的 node _ module 类似于:

generated npm package

但是我希望看到我所有的文件在包的根(没有该 dist文件夹)。我的 index.js文件在 dist文件夹中,但应该在根目录中。我试图将标签 files设置为 /dist/**/*,但是没有用。

我怎样才能做到呢?

85797 次浏览

我有同样的愿望,但我认为 只使用 npm 工具是无法实现这一点的。另一个脚本/工具可以用来安排你的软件包。

替代方案

目前我正在复制我的 package.jsondist文件夹,然后在 dist文件夹中运行 npm pack。我认为这基本上提供了我们所期望的一揽子安排。

下面是关于这个 npm 设计的一些相关阅读: 为什么 Node 中没有 Directories.lib

值得注意的是,jspm DOES 尊重 package.json中的 directories.lib选项,并在解析 npm 包时重新排列文件。这一切都是因为我想构建一个可以被 jspm 或 npm/webpack 使用的通用库。

我强烈建议您使用 .npmignore,而不是到处移动或复制内容,特别是如果您使用 CI 进行部署,那么只需在其中添加您不想发布的文件。

Https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package

例如:

#tests
test
coverage


#build tools
.travis.yml
.jenkins.yml
.codeclimate.yml


#linters
.jscsrc
.jshintrc
.eslintrc*


#editor settings
.idea
.editorconfig

更新:

如果你想分割你的代码,到不同的 npm 包使用相同的回购,我碰到了这个项目最近: 蕾娜,看起来真的很好。

也许你该看看

我有一个与原始海报(@robsonrosa)类似的问题。在我的例子中,我使用类型脚本,它编译成一个 dist目录。虽然我可以将类型脚本编译到根目录,但我认为最好的解决方案是在 dist 目录中生成一个单独的 package.json文件。
这类似于@scvnc 提出的复制 package.json的建议,但有一点不同:

作为打包过程的一部分,您应该为包生成一个 package.json,它基于但不同于根目录中的主 package.json文件

理由如下:

  • package.json文件是开发文件。它可能包含对包用户没有用处的脚本或开发依赖项,但可能会引起您的安全问题。您的打包过程可能包含从生产 package.json中去除该信息的代码。
  • 您可能希望将包部署到不同的环境,这些环境可能需要不同的包文件(例如,您可能希望拥有不同的版本或依赖项)。

- 编辑

我在评论中被要求提供一个解决方案。这是我正在使用的一些代码。这应该被视为一个例子,它并不意味着是一般的,是我的项目特有的。

我的设置:

package.json         - main package.json with dev dependencies and useful scripts.
.npmignore           - files to ignore; copied to 'dist' directory as part of the setup.
/src                 - directory where my typescript code resides.
/src/SetupPackage.ts - bit of code used to setup the package.
/dist                - destination directory for the compiled javascript files.

我只想打包 dist目录,并且该目录应该是包中的根目录。

我的 src目录中的文件 SetupPackage.ts将通过输入脚本编译成 dist目录中的 SetupPackage.js:

import fs from "fs";


// DO NOT DELETE THIS FILE
// This file is used by build system to build a clean npm package with the compiled js files in the root of the package.
// It will not be included in the npm package.


function main() {
const source = fs.readFileSync(__dirname + "/../package.json").toString('utf-8');
const sourceObj = JSON.parse(source);
sourceObj.scripts = {};
sourceObj.devDependencies = {};
if (sourceObj.main.startsWith("dist/")) {
sourceObj.main = sourceObj.main.slice(5);
}
fs.writeFileSync(__dirname + "/package.json", Buffer.from(JSON.stringify(sourceObj, null, 2), "utf-8") );
fs.writeFileSync(__dirname + "/version.txt", Buffer.from(sourceObj.version, "utf-8") );


fs.copyFileSync(__dirname + "/../.npmignore", __dirname + "/.npmignore");
}


main();

这个文件:

  • 复制根 package.json,但删除包中不需要的脚本和开发依赖项。它还修复了包的主入口点。
  • 将包的版本从 package.json写入名为 version.txt的文件。
  • 从根目录复制 .npmignore文件。

Npmignore 的内容是:

*.map
*.spec.*
SetupPackage.*
version.txt

例如,单元测试(规格文件)和类型脚本映射文件以及它创建的 SetupPackage.js文件和 version.txt文件被忽略。这样就没问题了。

最后,主 package.json文件有以下脚本供构建系统使用(假设使用 sh作为 shell)。

"scripts": {
"compile": "tsc",
"clean": "rm -rf dist",
"prebuildpackage": "npm run clean && npm run compile && node dist/SetupPackage.js",
"buildpackage": "cd dist && npm pack"
},

为了构建软件包,构建系统克隆回购,执行 npm install,然后运行 npm run buildpackage,反过来:

  • 删除 dist目录,确保编译是干净的。
  • 将类型脚本代码编译为 javascript。
  • 执行为打包准备 distSetupPackage.js文件。
  • Cds 到 dist目录,并在那里构建包。

我使用 version.txt文件作为获得 package.json 中的版本和标记我的回购的简单方法。有数不清的其他方法可以做到这一点,或者您可能想要自动增加版本。如果 SetupPackage.ts.npmignore对您没有用处,请删除它。

如果你的项目有 git,你可以使用小黑客。 将下一个脚本添加到 package.json

    "prepublishOnly": "npm run build && cp -r ./lib/* . && rm -rf ./lib",
"postpublish": "git clean -fd",

现在,当您运行 publish命令 npm 时,使用 prepublishOnly。它生成文件并将其保存到 lib文件夹(生成脚本取决于您的项目)。下一个命令将文件复制到根文件夹并删除 lib。发布 postpublish脚本之后,将项目返回到以前的状态。

cd TMPDIR
npm pack /path/to/package.json

Tarball 将在 TMPDIR 目录中创建。

这里还有一个方法,我认为是最干净的。它完全基于配置,不需要移动文件或在构建和打包脚本中指定路径:

package.json 指定主文件。

{
"main": "lib/index.js",
}

一些额外的打字稿选项:

  • 指定 rootDir。这个目录将包含所有的源代码,并且它应该包含一个 index文件(或者其他一些您可以在 package.json中用作 main 的文件)。
  • 指定 outDir。这是将要构建 tsc 命令的位置

tsconfig.json

{
"compilerOptions": {
"rootDir": "src",
"outDir": "lib",
},
...


}

只需创建一个 .npmignore文件并添加以下内容:

*.*
!dist/*

选项1: 导航到文件夹并执行“ npm Publishing.”命令

选项2: 运行 npm 发布/路径/目录

您需要发布 dist文件夹

根据 npm 方法,实现这一点的自然方法是发布作为根目录的文件夹。有几种方法可以做到这一点,这取决于您想使用的最终环境:

  1. 从您的软件包 repo 发布 < 文件夹 > 到一个 npm 注册中心,然后在安装其他软件包时在其他项目中安装您的软件包。对你来说是 npm publish dist
  2. 如果您只想在本地使用您的软件包,那么可以在其他项目中使用 npm install < file > 。在您的情况下,转到另一个项目并运行 npm install relative/path/to/dist
  3. Npm 链接 您的文件夹本地到另一个项目中的 node_modules,以防您希望原始包中的更改立即反映到其他项目中。在您的例子中,您首先运行 cd dist并运行 npm link,然后转到另一个项目并运行 npm link robsonrosa-ui-alert

先决条件 : 在任何情况下,在发布/安装/链接之前,您必须在 dist文件夹中至少放置一个适当的 package.json文件。在您的示例中,必须将 package.json 文件中的包名定义为 "name": "robsonrosa-ui-alert"。通常,还需要一些其他文件,如 README.md 或 LICENSE。

方法2及3的注释

使用以这种方式安装的包时,通常会出现包依赖性问题。为了避免这种情况,首先用 npm pack dist打包该包,然后从打包的 tarball (即 npm install path/to/package-tarball.tgz)中将该包安装到目标项目中。

自动化示例

您可以使用结合了 build脚本的 prepare脚本自动化发布过程。此外,您还可以保护您的软件包免受意外发布软件包根文件夹的影响,将 "private": true字段放在 package.json 中,该字段位于您的软件包 repo 的根目录中。这里有一个例子:

  "private": true,
"scripts": {
"build": "rm -rf dist && gulp build && cat ./package.json | grep -v '\"private\":' > dist/package.json",
"prepare": "npm run build"
},

这样,您就不会在发布过程中发布根文件夹并自动构建包和将 package.json 复制到 dist文件夹。

如果您正在使用(我建议) 语义释放,请在 .releaserc.json文件中添加 pkgRoot选项。(你也应该安装 Rjp) :

{
"pkgRoot": "dist",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/npm",
[
"@semantic-release/exec",
{
"prepareCmd": "npx rjp package.json version nextRelease.version"
}
],
[
"@semantic-release/git",
{
"message": "Release <%= nextRelease.version %> [skip ci]",
"assets": ["package.json", "CHANGELOG.md"]
}
],
"@semantic-release/changelog"
],
}

这样问题就解决了。只要确保您的 dist文件夹包含一个 package.json文件。通过在 postbuild脚本中添加一个 cp,您可以很容易地做到这一点:

{
"scripts": {
"postbuild": "cp package.json dist"
}
}

我通过以下方式实现这一目标:

  1. 我把我的 package.json设置为 private。所以我不能用 npm publish发布我的软件包
  2. 我用以下步骤创建一个 gulpfile:
import gulp from 'gulp';
import shell from 'gulp-shell';
import replace from 'gulp-replace';


const compile = () => gulp.src('package.json').pipe(shell('npm run compile'));


const copy = () => gulp.src(['readme.md']).pipe(gulp.dest('dist'));


const update = () =>
gulp.src('package.json').pipe(replace('"private": true,', '"private": false,')).pipe(gulp.dest('dist'));


const publish = () => gulp.src('package.json').pipe(shell('cd dist && npm publish'));


export default gulp.series(compile, copy, update, publish);

这对我有用

npm run build
cp package.json dist
cp .npmrc dist
cd dist
npm publish

我正在使用 Jenkins 的这些命令来发布软件包。

下面是简单的 package.json解决方案:

{
"scripts": {
"pack": "mkdir -p dist && cp package.json dist/package.json && npm pack ./dist",
"pub": "npm publish $(node -p \"p=require('./package.json');p.name+'-'+p.version+'.tgz'\")"
}
}

我有一个类型脚本项目,它编译成一个文件夹称为 dist和我已经找到了一个解决方案的 Windows。

在我的 package.json项目的根源:

  "scripts": {
"prepub": "copy package.json dist",
"pub": "cd dist & npm publish",
"postpub": "cd dist & del package.json"
}

这些脚本允许我通过运行 npm run pubdist文件夹发布为包的根目录。

  • prepub将 package.json 复制到 dist文件夹中。
  • pub将工作目录改为 dist/,然后运行 npm publish
  • postpub从我的 dist文件夹中删除 package.json,以确保每次发布都是干净的。

这样,我仍然可以在项目根目录中保留所有相关的配置文件,但是我可以在发布之前将它们复制到 dist

同样的方法可能也适用于 Mac 或 Linux。

您可以指定希望发布的目录。

  "scripts": {
"prepub": "rm -rf dist && tsc && cp package*.json dist",
"pub": "npm publish ./dist"
}

感谢@EnderShadow8的启发。

我的情况与此类似,但同时也更加复杂,因为它涉及到通过 CI 管道发布内容,而这个管道基本上不在我的控制范围之内,而且它在执行过程中下载了一个 .npmrc文件,只有它拥有发布权限。由于它必须与无数其他团队和存储库共享,因此它必须与每个存储库的细节不可知。

在花费了大量时间尝试将 .npmrc文件复制到 npm 的全局根目录之后,这个全局根目录往往以权限警告结束,在 package.json中尝试使用不同的脚本来调用全局 npm,结果得到403个 HTTP 错误,最后我终于想到了解决方案,如果我尝试的话,它不可能再简单了。

它所需要做的就是在应用程序中包含一个 shell 脚本(如果容器运行 Windows,也可以是一个批处理文件) ,检查它在管道中是否存在,并运行它而不是 npm publish

由于现在 npm publish [folder]语法已经存在,所以我的脚本非常简单,但是我可以看到在不同的时间它看起来如何像 @ Eli Algranti’s脚本。

结果是这样的:

出版

# DO NOT EDIT THIS FILE
# THIS OVERRIDES THE DEFAULT PIPELINE PUBLISH SCRIPT TO BE RUN
# IT EXISTS SO ONLY THE BUILD OUTPUT FOLDER GETS PUBLISHED
npm publish ./dist

Npm-build. yml

npm run build --if-present


if [ -f "./publish.sh" ]; then
echo "'publish.sh' script has been found. Overriding the publishing with it"
sh publish.sh
else
npm publish
fi

这在本地运行,包含当前用户和已经复制的 .npmrc文件,并且可以在必要时封装许多其他逻辑