使用webpack输出可执行文件

7

我目前正在编写一个Node CLI工具,并使用webpack打包所有资源。此应用程序的入口点是实际解析process.argv并运行命令的js文件(参考:tj/commander)。这样,一旦打包完成,我就可以输入./<outputFile>,然后它将运行我的应用程序。入口文件如下:

import cli from './cli';

cli.parse(process.argv);

// If nothing was supplied
if (!process.argv.slice(2).length) {
  cli.outputHelp();
}

打包工作正常,但是我无法让webpack将文件输出为可执行文件。一旦我运行chmod +x <outputFile>,一切都完美地运行。有没有办法告诉webpack授予输出文件什么权限?

5个回答

9

我很惊讶没有人提到webpack的BannerPlugin。我做的事情与@oklas类似,但是使用BannerPlugin来添加特定的节点shebang:

{
  plugins: [
    new webpack.BannerPlugin({
      banner: '#!/usr/bin/env node',
      raw: true,
    }),
  ],
}

然后,我只需在我的package.json文件中添加chmod即可添加执行权限:

"scripts": {
  "build": "webpack && chmod +x dist/mycommand"
}

无论如何,如果您想只使用webpack,可以使用WebpackShellPlugin,正如oklas所说(请注意,使用此方法会强制您添加新的依赖项,这就是为什么我避免使用此方法的原因):

const WebpackShellPlugin = require('webpack-shell-plugin')
{
  // [...]
  plugins: [
    new WebpackShellPlugin({
      onBuildEnd:['chmod +x dist/mycommand'],
    }),
  ],
}

如果你想避免将WebpackShellPlugin作为依赖项,请尝试根据@taylorc93所说,基于fs定义自定义插件。

6
一种简单的方法是使用npm。您的项目中是否有package.json文件?在package.jsonscripts部分添加"build": "webpack && chmod +x outputFile",然后通过运行npm run build来构建您的项目。
另一种方法是将以下解决方案之一添加到您的webpack.config.js中: 无论您选择哪种方法,都需要添加以下代码片段:
var chmod = require('chmod');
chmod("outputFile", 500);

我之前并没有考虑过这个选项。如果可能的话,我想要将所有内容都保留在webpack中。如果接下来的一两天内没有其他人发布webpack特定的解决方案,我会接受这个答案,因为它肯定能解决我的问题。 - taylorc93

3

您需要在文件顶部添加#!/usr/bin/env node。我最终使用了这个webpack插件,使用shelljs

plugins: [
  // ...plugins,
  function () {
      this.plugin('done', () => {
      shell
        .echo('#!/usr/bin/env node\n')
        .cat(`${__dirname}/build/outputfile.js`)
        .to(`${__dirname}/commandname`)
      shell.chmod(755, `${__dirname}/commandname`)
    })
  },
]

2

虽然@oklas的解决方案对我来说完美无缺,但我真的想尝试将所有内容都保留在webpack中。 经过更多思考后,我意识到这可以通过一个非常简单的插件完成:

plugins: [
  // ...plugins,

  function() {
    this.plugin('done', () => {
      fs.chmodSync('bin/program-name.js', '755');

      // When the webpack output doesn't have a .js extension, minification fails :(
      fs.renameSync('bin/program-name.js', 'bin/program-name');
    })
  },
]

使用适合您需求的任何方法!


1
这是我使用Webpack 5的方法:
import { promises as fs } from 'fs';

plugins: [
    new webpack.BannerPlugin({
        banner: '#!/usr/bin/env node',
        raw: true,
        entryOnly: true
    }),
    function() {
        this.hooks.done.tapPromise('Make executable', async () => {
            await fs.chmod(`${__dirname}/dist/app.js`, '755');
        });
    }
]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接