How to search/replace text with brunch using a regex? - brunch

Is there any way to search/replace arbitrary text with brunch using a regex? The keyword-brunch plugin exists but it only works if you are replacing a keyword enclosed as {!keyword!}. With Grunt there exists plugins such as grunt-sed. Does anything like this exist for brunch?

It would be pretty straightforward to write an optimizer or onCompile plugin to do this, but there are other approaches too that you might find more appealing.
For instance, you mentioned grunt-sed, which is backed by the replace npm package and happens to have a CLI. So you could install that package into your project and set an npm script to run the command you want.
In your package.json
"scripts": {
"replace": "replace 'foo' 'bar' public -r"
}
and then trigger it to run at the end of every Brunch compile cycle using the after-brunch plugin
plugins:
afterBrunch: [
'npm run replace'
]

Related

npm workspaces "WARN: some-package-name in filter set, but no workspace folder present"

I have a repo with many npm packages inside, using npm workspaces
The top-level package.json contains the line:
"workspaces": [
"*"
]
When I run npm i -ws or other npm commands, I receive the warning:
WARN: some-package-name in filter set, but no workspace folder present
I'm not quite sure what the message means - I think the 'filter set' is the -w option, but the workspace folder some-package-name definitely exists.
One note is that the some-package-name/package.json contains an org prefix, eg:
"name": "#mycompany/some-package-name",
So maybe that's the cause. I can't rename the folder from some-package-name to #mycompany/some-package-name though as I'm concerned a directory starting with # may break things.
What does the warning mean and how can I resolve it?
I ran into the same problem, using the name configured in the workspace's package instead of the folder name fixed the issue for me, even with an #.
npm install --workspace=#mycompany/some-package-name
I have a slightly different answer.
I'm creating a package.json programatically, using Fs.writeFileSync('./path/to/package.json').
I run npm install -w=workspace foo bar immediately after, but it seems that this fails sometimes; NPM somehow hasn't picked up on the file, as if I run the same command twice, the second one always works.
Adding a small delay using setTimeout() also works, though I feel a bit dirty having had to do this; I don't know if this is an issue with Node or my lack of knowledge around Node's process lifecycle.
Anyway, in this case – and in lieu of better solution – it works.
I solved this issue using a file: dependency as "recommended by npm" (read below).
Actually many articles say that npm recommends to use file: to reference a dependency between two workspace packages (and then often they use the asterisk anyway) but honestly I did not found that hint in npm docs, but it works! ... at least it worked for me, using the following
Explicitly list the workspaces
So instead of using an asterisk I have, for example
"workspaces": [
"packages/models",
"packages/database",
"webapp"
]
I also have a scoped package name
for instance
"name": "#project/models",
"private": "true"
I am using "file:" dependencies
Instead of
"dependencies": {
"#project/models": "*"
}
I use file:WORKSPACE_PATH
"dependencies": {
"#project/models": "file:packages/models"
}

How can I pass a string as an argument to an NPM script that is then passed to a CLI command?

I'm setting up a new react project, and I'd like to use the generate-react-cli package so that I can easily generate components instead of manually having to create files.
However the command to run the tool is lengthly, so I'd like to cut that down using an NPM script. The command is npx generate-react-cli component Box
So preferably I'd like to be able to do something like npm run grc Box and then have "Box" be passed as an argument to an NPM script that looks like
"scripts": {
"grc-c": "npm generate-react-cli component $1"
},
I've tried this using -- parameters but it didn't work as it parses it incorrectly.
You can revert the script to:
"scripts": {
"grc-c": "npm generate-react-cli component"
},
And use:
npm run grc-c -- Box

How to run node.js cli with experimental-specifier-resolution=node?

Our team has built a small CLI used for maintenance. The package.json specifies a path for with the bin property, and everything works great; "bin": { "eddy": "./dist/src/cli/entry.js"}
Autocompletion is achived by using yargs#17.0.1. However we recently converted the project to use es6 modules, because of a migration to Sveltekit, i.e. the package.json now contains type: module. Because of this, the CLI now only works if we run with:
what works
node --experimental-specifier-resolution=node ./dist/src/cli/entry.js help
However, if we run this without the flag, we get an error "module not found":
Error [ERR_MODULE_NOT_FOUND]: Cannot find module...
So the question is
Can we somehow "always" add the experimental-specifier-resolution=node to the CLI - so we can continue to use the shorthand eddy, and utilize auto completion?
There are two probable solutions here.
Solution 1
Your entry.js file should start with a shebang like #!/usr/bin/env node. You cannot specify the flag directly here, however, if you could provide the absolute path to node directly in the shebang, you can specify the flag.
Assuming you have node installed in /usr/bin/node, you can write the shebang in entry.js like:
#!/usr/bin/node --experimental-specifier-resolution=node
(Use which node to find the absolute path)
However, this is not a very portable solution. You cannot always assume everyone has node installed in the same path. Also some may use nvm to manage versions and can have multiple version in different path. This is the reason why we use /usr/bin/env to find the required node installation in the first place. This leads to the second solution.
Solution 2
You can create a shell script that would intern call the cli entry point with the required flags. This shell script can be specified in the package.json bin section.
The shell script (entry.sh) should look like:
#!/usr/bin/env bash
/usr/bin/env node --experimental-specifier-resolution=node ./entry.js "$#"
Then, in your package.json, replace bin with:
"bin": { "eddy": "./dist/src/cli/entry.sh"}
So when you run eddy, it will run the entry.js using node with the required flag. The "$#" in the command will be replaced by any arguments that you pass to eddy.
So eddy help will translate to /usr/bin/env node --experimental-specifier-resolution=node ./entry.js help
Just add a script to your package.json:Assuming index.js is your entry point and package.json is in the same directory
{
"scripts": {
"start": "node --experimental-specifier-resolution=node index.js"
}
}
Then you can just run on your console:
npm start

Is it possible to consume environment variables inside of npm / package.json?

I'm attempting to build a package.json so that when running a NodeJS app on Heroku it will run the scripts.postinstall step using an environment variable. For example:
...
"scripts": {
"postinstall": "command $ENV_VAR"}
},
...
I've looked at the docs and wasn't able to find something saying I can.
Is this even possible? Is this even desirable and "I'm Doing It Wrong"™?
Ignore the nay-sayers. You can do this in a cross-platform manner using cross-var:
"scripts": {
"postinstall": "cross-var command $ENV_VAR"
}
Updated answer due to new packages having been written
You can use the cross-var package to do this in a clean way:
...
"scripts": {
...
"postinstall": "cross-var command $ENV_VAR",
...
},
"dependencies": {
...
"cross-var": "^1.1.0",
...
}
...
Original answer
To answer the last questions, because they're the most important one: yes, no, and absolutely, because you've just broken cross-platform compatibility. There is no guarantee your environment syntax works for all shells on all operating systems, so don't do this.
We have a guaranteed cross-platform technology available to us already: Node. So, create a file called something like bootstrap.js, and then make npm run node bootstrap as your postinstall script. Since the code inside bootstrap.js will run like any other node script, it'll have access to process.env in a fully cross-platform compatible way, and everyone will be happy.
And many, many, many things that use common utils have node equivalents, so you can npm install them, locally rather than globally, and then call them in an npm script. For instance mkdir -p is not cross-platform, but installing the mkdirp module is, and then an npm script like "ensuredirs": "mkdirp dist/assets" works fine everywhere when run as npm run ensuredirs
And for convenience, the most common unix utilities have their own runner package, shx, which is fully cross-platform and makes the lives of devs even easier, with the "if you're writing code" equivalent being fs-extra.

npm postinstall fails with multiple commands

Inside my composer.json, there's a postinstall hook setup like the following:
"scripts" : {
"dist" : "node dist; node_modules/.bin/doccoh src/package.js",
"postinstall" : "node_modules/.bin/grunt setup || true; node_modules/.bin/bower install",
"start" : "node server.js"
}
Whenever I run it (on Win from Git/Gnu Bash CLI), I end with
command not found. either the command was written wrong or couldn't be found
Rough translation from German CLI error.
I tried splitting it into multiple ;/semicolon separated parts and first cd into that directory, but it simply ends up with the same error message. Replacing the whole postinstall command set with a simple ls does work. So I guess the problem might be the semicolon separation or a wrong usage of commands. But overall I got no idea what's wrong.
Note: I got grunt-cli version 0.1.9 and grunt version 0.4.1 installed globally.
I'm a bit late to answer, but if you're on Windows, multiple commands on a single line are executed with the use of &&
postinstall: "some command && some other -c"
I ran into this looking for something and thought this may help other people. I have found it easier to move to postinstall.js files as things get a little complicated. This makes it easier to deal with moving forward.

Resources