【问题标题】:How to npm publish specific folder but as package root如何npm发布特定文件夹但作为包根
【发布时间】:2016-12-20 11:36:45
【问题描述】:

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

如果你在数组中命名一个文件夹,那么它也会包含文件 在那个文件夹里面

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

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

我怎样才能实现它?

【问题讨论】:

    标签: npm package node-modules package.json


    【解决方案1】:

    我也有同样的愿望,但我认为 仅使用 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、files 和 main 属性来实现。我想将所有文件移动到根目录并且没有 dist 文件夹
    【解决方案2】:

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

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

    理由:

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

    --- 编辑 ---

    我被要求在 cmets 中寻求解决方案。所以这是我正在使用的一些代码。这应该被视为一个示例,它并不是通用的,而是特定于我的项目的。

    我的设置:

    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"
      },
    

    要构建包,构建系统会克隆 repo,执行npm install,然后运行npm run buildpackage,这反过来:

    • 删除dist 目录以确保编译干净。
    • 将 typescript 代码编译为 javascript。
    • 执行准备dist 进行打包的SetupPackage.js 文件。
    • cds 到dist 目录并在那里构建包。

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

    【讨论】:

    • 这个答案看起来是最好的,但是除了理论,你有现成的解决方案吗?
    • @yumaa 我用一个具体的例子编辑了我的答案。希望有用。
    • 对我进行了一些更改。当前SetupPackage.ts 文件将文件复制到src 目录而不是dist。谢谢?
    • 所以... 99.9% 的开放项目中的 package.json 不应该“签入”package.json..?处理 package.json 及其中所有内容的正确方法是确保它不包含秘密/静态值(此类值应由 CI 作为输入/环境变量等提供......)
    【解决方案3】:

    如果你的项目有 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
    【解决方案4】:

    如果您(我推荐)使用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 文件即可。您可以通过在您的 postbuild 脚本中添加 cp 轻松做到这一点:

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

    【讨论】:

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

    我强烈建议您使用 .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
    • yeh material UI 使用它,我用过这个。我的上一家公司,我发现它没问题
    【解决方案6】:
    cd TMPDIR
    npm pack /path/to/package.json
    

    压缩包将在 TMPDIR 目录中创建。

    【讨论】:

    • ^这个答案被低估了。 npm pack 加上 package.json files 字段(或 .npmignore)效果很好。
    【解决方案7】:

    您需要发布dist 文件夹

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

    1. npm publish <folder> 从你的包 repo 到 npm 注册表,然后在安装其他包时将你的包安装到其他项目中。在您的情况下,它将是 npm publish dist
    2. npm install <folder> 如果您只想在本地使用您的包,请在其他项目中使用。在您的情况下,您转到另一个项目并运行npm install relative/path/to/dist
    3. npm link 您的文件夹在另一个项目中本地到您的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 script 结合build 脚本自动执行发布过程。此外,您可以通过将 "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 文件夹。

    【讨论】:

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

    我有一个 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。

    【讨论】:

      【解决方案9】:

      这对我有用

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

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

      【讨论】:

        【解决方案10】:

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

        【讨论】:

          【解决方案11】:

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

          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);

          【讨论】:

            【解决方案12】:

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

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

            感谢@EnderShadow8 的启发。

            【讨论】:

              【解决方案13】:

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

              package.json 指定主文件。

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

              一些额外的打字稿选项:

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

              tsconfig.json

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

              【讨论】:

              • 除了将名称从 dist 更改为 lib 之外,这与 OP 原来的不一样吗?
              【解决方案14】:

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

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

              【讨论】:

                【解决方案15】:

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

                *.*
                !dist/*
                

                【讨论】:

                • 这是否符合 OP 的要求?我无法让它工作。这个想法是让发布的包只包含 dist 目录的内容,而不包括目录本身。我这样做是为了确保我们不包含 dist 目录中已经可以使用 package.json “文件”列表完成的任何内容。
                猜你喜欢
                • 2019-11-25
                • 2023-04-03
                • 2018-02-05
                • 2020-08-20
                • 1970-01-01
                • 1970-01-01
                • 2019-08-28
                • 2018-05-03
                • 2019-04-22
                相关资源
                最近更新 更多