6

I'm currently writing a node CLI tool and using webpack to bundle all of my assets. The entry point for this application is the js file where I actually parse process.argv and run a command (For reference, I'm using tj/commander). This way, once the bundling is complete, I can enter ./<outputFile> and it will run my application. The entry file looks like this:

import cli from './cli';

cli.parse(process.argv);

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

The bundling works fine but I can't get webpack to output the file as an executable. Once I run chmod +x <outputFile>, everything works perfectly. Is there a way that I can tell webpack what permissions to grant an output file?

taylorc93
  • 3,366
  • 2
  • 17
  • 33

4 Answers4

7

I'm surprised no one said a thing about webpack's BannerPlugin. I do something similar than @oklas, but using BannerPlugin to add the specific node shebang:

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

Then I simply add the execution permissions just adding chmod to my package.json file:

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

Anyway, if you'd like to just use webpack you can use the WebpackShellPlugin, as said by oklas (note that using this forces you to add a new dependency, that's why I avoid using this approach):

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

If you want to avoid including WebpackShellPlugin as a dependency, you can try to define a custom plugin based on fs, as said by @taylorc93

elboletaire
  • 4,023
  • 2
  • 31
  • 43
5

One simple way is to use npm. Do you have an package.json in your project? Add "build": "webpack && chmod +x outputFile" to the scripts section of your package.json and build your project by running npm run build.

Another way is to add one of these solutions to your webpack.config.js:

Whatever you choose, you'll need to add this piece of code:

var chmod = require('chmod');
chmod("outputFile", 500);
Community
  • 1
  • 1
oklas
  • 6,279
  • 2
  • 21
  • 36
  • I do and had not considered that as an option. I'd like to, if possible, keep it all within webpack. If no one else posts a webpack-specific solution in the next day or 2, I'll accept this answer as it will definitely solve my problem. – taylorc93 Jan 23 '17 at 19:40
3

You'll need to append #!/usr/bin/env node on top of the file.
I ended up with this webpack plugin using 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`)
    })
  },
]
alfonsodev
  • 2,609
  • 1
  • 21
  • 29
2

Although @oklas's solution worked perfectly for me, I really wanted to try and keep all of this within webpack. I realized after a little more thought that this could all be done by a very simple plugin:

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');
    })
  },
]

Use whichever way suits your needs!

taylorc93
  • 3,366
  • 2
  • 17
  • 33