ChatGPT解决这个技术问题 Extra ChatGPT

如何 npm 发布特定文件夹但作为包根

我有一个项目,其中包含一个 gulp 任务,用于在名为 dist 的目录中构建和打包源代码和发布。我的目标是将它发布为一个 npm 包,但只发布我的 dist 文件夹。 npm documentation 表示我可以使用 files 标记来指定要导出的文件。有用。但是,文档还说:

如果您在数组中命名一个文件夹,那么它还将包括该文件夹内的文件

结果是一个 npm 包,它的 node_modules 看起来像:

https://i.stack.imgur.com/qWzv7.png

但我想在包的根目录(没有那个 dist 文件夹)查看我的所有文件。我的 index.js 文件位于 dist 文件夹中,但应该位于根目录下。我尝试将标签 files 设置为 /dist/**/*,但没有成功。

我怎样才能实现它?


C
Community

我有同样的愿望,但我认为仅使用 npm 工具是无法实现的。另一个脚本/工具可用于安排您的包裹。

替代解决方案

目前我正在将我的 package.json 复制到 dist 文件夹中,然后在 dist 文件夹中运行 npm pack。我认为这基本上提供了我们所需的包装安排。

以下是有关此 npm 设计的一些相关阅读:Why no Directories.lib in Node

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


(为什么没有 Directories.lib...)是死链接
为什么 Node 中没有 Directories.lib 说,如果你不按照我们的方式去做,你应该会感到痛苦。所有这一切都会产生对解决此问题的工具的需求。
我相信这个答案已经过时了。正如下面的回复所指出的,使用 npm pack、package.json filesmain 字段以及 .npmignore 为开发人员提供了从特定的可安装目录创建包所需的一切。
制作了一些 scripts 以简化/强制“发布子目录”模式
有人可以发布解决方案,如何使用 package.json 中的 npmignore、文件和主要属性来实现。我想将所有文件移动到根目录并且没有 dist 文件夹
E
Eli Algranti

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

作为打包过程的一部分,您应该为包生成一个 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 将通过 typescript 编译为 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。

执行为打包准备 dist 的 SetupPackage.js 文件。

cds 到 dist 目录并在那里构建包。

我使用 version.txt 文件作为获取 package.json 中的版本并标记我的存储库的简单方法。有无数其他方法可以做到这一点,或者您可能希望自动增加版本。如果对您没有用,请将其从 SetupPackage.ts.npmignore 中删除。


这个答案看起来是最好的,但是除了理论,你有现成的解决方案吗?
@yumaa 我用一个具体的例子编辑了我的答案。希望它是有用的。
为我工作了一些变化。当前的 SetupPackage.ts 文件将文件复制到 src 目录而不是 dist。谢谢👍
所以... 99.9% 的开放项目中的 package.json 不应该“签入”package.json ...?处理 package.json 及其中所有内容的正确方法是确保它不包含秘密/静态值(此类值应由 CI 作为输入/环境变量等提供...)
这是最好的答案之一,通过适当的设置,您可以随意配置它们,这样可以更好地控制 npm pack。
D
Den

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

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

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


我是这个解决方案的粉丝!
我真的很喜欢这个。此解决方案的最大问题是,如果在准备、预打包、打包、后打包和发布过程中出现任何故障,您的项目根目录中会留下一堆东西,您需要手动运行 git clean -fd
V
Vahid

如果您(并且我建议)使用 semantic-release,请在 .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 文件。您可以通过将 cp 添加到 postbuild 脚本来轻松做到这一点:

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

不错的解决方案!对此的补充如下。您可以将 prepareCmd 命令更改为:npm --no-git-tag-version version <%= nextRelease.version %>。这将更改 package.json 和 package-lock.json 中的版本。通过添加 --no-git-tag-version 标签,它不会创建 git 标签,也不会提交文件。
T
Thram

我强烈建议您使用 .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

更新:

如果您想使用相同的 repo 将代码拆分为不同的 npm 包,我最近遇到了这个项目:Lerna,看起来非常好。

也许你应该看看


我们仍然必须在包的根目录中发出我们构建的文件。也许 CI 是允许的。观察我链接到的 Isaac 博客中的帖子,告诉我您的解决方案如何允许使用 require('mypackage/foo') 而不是 require('mypackage/dist/foo')
我不是想在这里解决这个问题。如果你想拆分你的代码,我最近碰到了这个项目:lernajs.io,看起来真的很不错
找到另一个值得一看的工具 :) github.com/philcockfield/msync
是的,材料 UI 使用它,我用它。我的上一家公司,我发现它没问题
P
Pavindu
cd TMPDIR
npm pack /path/to/package.json

tarball 将在 TMPDIR 目录中创建。


^这个答案被低估了。 npm pack 加上 package.json files 字段(或 .npmignore)非常有效。
J
Jacek J

您需要发布 dist 文件夹

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

npm publish 从你的包 repo 到一个 npm 注册表,然后在你安装其他包时将你的包安装到其他项目中。在您的情况下,它将是 npm publish dist。如果您只想在本地使用您的包,请在其他项目中安装 npm install 。在您的情况下,您转到另一个项目并运行 npm install relative/path/to/dist 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

自动化示例

您可以使用 prepare scriptbuild 脚本自动执行发布过程。此外,您可以使用 package.json 中的 "private": true 字段来保护您的包免受意外发布包根文件夹的影响,该字段位于包存储库的根目录中。这是一个例子:

  "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 文件夹。


当我执行 npm publish dist 时,它会尝试推送名称为 dist 的包,而不是使用 dist 文件夹。
@Robin,但是您是否完成了我在 先决条件 部分中写的内容?即您是否已将 package.json 复制到您的 diist 文件夹中?
E
EnderShadow8

我有一个 Typescript 项目,它编译到一个名为 dist 的文件夹中,并且我找到了适用于 Windows 的解决方案。

在我的项目根目录的 package.json 中:

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

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

prepub 将我的 package.json 复制到 dist 文件夹中。

pub 将工作目录更改为 dist/ 然后运行 npm publish

postpub 从我的 dist 文件夹中删除 package.json 以确保每次都进行干净的发布。

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

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


k
kgreen

这是简单的 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'\")"
    }
}

A
Abhishek

这对我有用

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

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


G
Gideao

我通过执行以下操作来实现这一点:

我将 package.json 设置为私有。所以我不能用 npm publish 发布我的包我用以下步骤创建了一个 gulpfile:

从'gulp'导入gulp;从“gulp-shell”导入外壳;从“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'));导出默认 gulp.series(编译、复制、更新、发布);


T
Tiramonium

我的情况类似,但同时也更麻烦,因为它涉及通过 CI 管道进行发布,这几乎不受我的控制,并且只有它通过它在执行期间下载的 .npmrc 文件具有发布权限。而且由于它必须与无数其他团队和存储库共享,它必须与每个存储库的细节无关。

在浪费了大量时间试图将 .npmrc 文件复制到 npm 的全局根目录后,通常以权限警告结束,然后尝试在 package.json 中使用不同的脚本来调用全局 npm 并获得 403 HTTP错误,解决方案终于让我明白了,如果我尝试过,它再简单不过了。

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

由于现在存在 npm publish [folder] 语法,因此我的脚本非常简单,但我可以看到它在不同时期可能看起来像 @Eli Algranti's 脚本。

所以这就是它最终的样子:

发布.sh

# 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 文件,并且可以在必要时封装许多其他逻辑


s
scottmgerstl

这是我认为最干净的另一种方法。它全部基于配置,无需在构建和打包脚本中移动文件或指定路径:

package.json 指定主文件。

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

一些额外的打字稿选项:

指定根目录。该目录将包含所有源代码,并且其中应该有一个索引文件(或您可以在 package.json 中用作 main 的其他文件)。

指定 outDir。这是您的 tsc 命令将构建到的位置

tsconfig.json

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

}

除了将名称从 dist 更改为 lib 之外,这与 OP 最初的内容不一样吗?
S
Sasi Kumar M

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

选项 2:运行 npm publish /path/directory


V
Vaelin

您可以指定要发布的目录。这就是我在 Linux 上为 Typescript 提出的。

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

感谢@EnderShadow8 的启发。


B
BuZZ-dEE

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

*.*
!dist/*

这是否按照 OP 的要求进行?我无法让它工作。这个想法是让发布的包只包含 dist 目录的内容,而不包括目录本身。我这样做是为了确保我们不包含 dist 目录中已经可以使用 package.json “文件”列表完成的任何内容。