How can I make npm projects with Bash shell commands work on Windows?

Question

I have some NPM scripts on a project i recently took over that go like this:

{
    "package": "yarn package-common && mv './dist/APP® TV.wgt' ''./package/$(yarn -s filename)''",
    "package-common": "tizen package -t wgt -s APP -- ./dist && rimraf package && mkdir package",
    "filename": "cross-env-shell echo APP_${npm_package_version}.wgt",
}

This project was written by someone on a MAC. How can i translate the following part into a functioning Powershell / cmd command? I havent found anything anywhere about this. It runs the command and the echoed value gets appended to the string it got called from.

''./package/$(yarn -s filename)''

Or even better, is there a way besides this package to do it cross-platform?

Currently the message that gets output in powershell when running yarn package is:

'' was unexpected at this time.
Solution

Your basic choices for going cross-platform without platform-specific scripts are:

  • Use Bash also on Windows:

    • Run your npm scripts from Bash via WSL and use the existing Bash commands typically contained in package.json files, such as in your case.

    • Alternatively, with Git for Windows installed, configure npm to use bash.exe as the shell for invoking commands - see this answer [npm v5.1 ].

  • Install PowerShell Core on all your platforms (including Windows), and define the commands as PowerShell commands (see below) [npm v5.1 ].

Note the npm version version requirement (version 5.1 or higher) where noted, due to the configuration option to use a specific shell (script-shell) not being available in earlier versions. Run npm -v to get the installed version, and
npm install -g npm to update, if possible.


Using npm with PowerShell Core on all platforms [npm v5.1 ]:

  • Install PowerShell Core.

  • Then configure npm to use PowerShell Core as the shell (requires npm version 5.1 or higher):

    • For all your projects or globally:

      npm config set script-shell pwsh [--global]
      
    • For a given project only (from that project's root directory):

      npm config set script-shell pwsh --userconfig ./.npmrc
      
  • Finally, in your projects' package.json's scripts key, define the commands as PowerShell commands.

In the case at hand:

For instance, translate this Bash command:

yarn package-common && mv './dist/APP® TV.wgt' "./package/$(yarn -s filename)"

Note: I've replaced '' with ", because the latter make more sense; as originally written, the '' are effectively discarded by Bash, and the result of command substitution $(yarn -s filename) could break the command if it contained whitespace.

to this PowerShell command:

yarn package-common; if ($?) { mi './dist/APP® TV.wgt' "./package/$(yarn -s filename)" }

Note:

  • As of v6.2.0, PowerShell lacks Bash-style && and || operators, hence the use of if ($?) to check for successful execution of the previous command explicitly - see this suggestion on GitHub for making PowerShell support && and || too.

  • mi is a built-in alias for the Move-Item cmdlet.

  • While it makes sense to call your scripts from PowerShell also, that's not a requirement - calling from cmd.exe or a batch file will work too.

  • To get started with PowerShell Core, see Learning PowerShell; also, http://hyperpolyglot.org/shell juxtaposes the syntax of POSIX-like shells such as Bash with that of cmd.exe and PowerShell in concise, tabular form.