How to shim npm package dependency in browserify? - node.js

So I have a React project, in which I'm actually deploying with react-lite as the footprint is much smaller. I'd like to use react-nouislider, but in it's package.json, I've found this:
"peerDependencies": {
"react": "^0.14.0"
}
What this means is that whenever I require react-nouislider, it pulls in React instead of react-lite. How do I shim dependencies of an npm package from my top-level package.json?
This is how I'm shimming react-lite in:
"browser": {
"react": "react-lite"
}
And I tried this, but it didn't work:
"browserify-shim":{
"react-nouislider": {
"depends": "react-lite"
}
}
How is it possible to shim a dependency of a package itself?

Browserify Shim's tagline is:
Makes CommonJS incompatible files browserifyable.
Your issue here is that react-lite is already CommonJS compatible. For any CommonJS compatible file, Browserify will automatically add its dependencies and peerDependencies as appropriate, before Browserify Shim gets involved.
I suggest you change the peerDependencies entry in the react-nouislider package to the appropriate version of react-lite and remove your Browserify Shim config above as it's no longer needed. When you do this, be sure to run any tests in the react-nouislider package to make sure it still works with react-lite instead of React. A good way of doing this is forking react-nouislider to your own repo, making the change there, and pulling from that repo in your package.json.

Related

yarn uses wrong version on workspaces

I have a huge project, which I was will simplify for the issue, with 2 workspaces.
The main packages looks like
workspaces: [ 'workspace-A', 'workspace-B' ]
My workspace-A has a dependency to external package (here, jest), in a needed version
name: "workspace-A",
dependencies: {
"jest": "<27.0.0"
}
My workspace-B has a dependency to the same package, but doesn't care about its version.
name: "workspace-B"
dependencies: {
"jest": "*"
}
After a yarn install (with yarn v3), I was expecting yarn to automatically install jest with a 26.x.x version in my main node_modules.
Instead, the node_modules of the main project contains jest 26.x.x, and the node_modules of the workspace-B contains jest 27.x.x. It's OK for my, even if I find this weird, but the thing is the workspace-A now uses jest 27.x.x!
I succeeded make it work by adding a resolution field in the main package file, but it's not ideal, as this package doesn't need jest.
"resolutions": {
"jest": "^26.6.3",
}
My 2 questions are
Why is yarn installing 2 versions of jest, is there a way to prevent this?
Is there a configuration somewhere I should put to specify to the workspace-A to not use something from workspace-B?
Thanks for reading

How to patch jest-rutime when using Yarn 2?

I am trying to follow the instructions in this repository to patch Jest.
Patch Jest.
It is suggested to use patch-package but I figured out that I can use yarn patch when using Yarn 2.
I managed to patch jest-runtime but seems Jest doesn’t seem to require jest-runtime in its package so I don’t know where it comes from to use it as a reference to declare the patched file.
Jest package.json
I understand if Jest was the one that needs to be patched I could declare it like this:
package.json
"devDependencies": {
"jest": "patch:jest#26.6.3#./patches/jest.patch"
}
I tried to use the same logic to include the following code to include jest-runtime but it didn't work.
"devDependencies": {
"jest": "^26.6.3",
"jest-runtime": "patch:jest-runtime#26.6.3#./patches/jest-runtime.patch"
}
How can I declare this patched jest-runtime so Jest can use it?
The Resolutions field in the manifest is the correct approach to declare the patched modules that we didn't add to devDependencies such as submodules.
The resolutions field allows you to instruct Yarn to use a specific resolution instead of anything the resolver would normally pick. This is useful to enforce all your packages to use a single version of a dependency, or backport a fix.
The fix for that issue:
{
...
"dependencies": {
"jest": "^26.6.3",
},
"resolutions": {
"jest-runtime": "patch:jest-runtime#26.6.3#./patches/jest-runtime.patch"
},
}

What is the correct way of adding a dependency to react in your package.json for a react component

I have made a few simple reusable react components and wanted to know the correct way to include a dependency to react in my package.json for publishing with npm.
I am currently doing this:
Assuming my component will use the most recent version of react and I have tested and it works with that version. e.g. 0.13.3
"peerDependencies": {
"react": "^0.13.3"
},
For reusable components:
Put a react dependency in both peerDependencies and devDependencies.
Never put a react dependency in dependencies.
peerDependencies specifies which version(s) of React your reusable component supports/requires. When using npm 2 this also adds React to the list of modules to be installed, but this is no longer the case with npm 3.
devDependencies ensures React will be installed when you run npm install while developing your component, or when running tests on Travis or similar.
Putting react in dependencies will cause multiple versions of React to be installed if somebody uses your component but has a different version of React in their own package.json - having multiple versions of React not only bloats the build, but also causes errors when different versions try to interact.
The selected answer is definitely the prescribed approach here however I've started favoring the use of inversion of control as opposed to relying on npm peer dependencies for my libraries dependencies and its served me well.
Libraries are easier if you build them functional. It seems to be easier to maintain libraries that export a single function which takes in an object with all of their heavy dependencies and export an object containing each of your libraries typical exports.
Library 'injected'
lib/index.js
export default ({ React }) => {
const InjectedComponent = props => (
<p style={{color: props.color}}>This component has no React npm dependencies.</p>
)
/** other stuff */
return { InjectedComponent }
}
Consuming App
app.js
import React from 'react'
import { render } from 'react-dom'
/** Import the default export factory from our library */
import createInjectedComponent from 'injected'
/** Call the factory, passing its dependencies (guaranteed to match what we're bundling) and get back our component */
const { InjectedComponent } = createInjectedComponent({ React })
render(<InjectedComponent color="blue" />, document.getElementById('root'))
If your component only works with a given version of react or some other dependency, you can write some assertions around the version for the React parameter that is passed in. Overall, building libraries in this fashion should be less prone to new build issues appearing anytime version of React is published and will more importantly ensure that you are not causing your library consumers to bundle multiple versions of React and other heavy libraries. This pattern works well with npm link (I generally have 16+ libraries running from npm link simultaneous and experienced issues when I didn't use this pattern).
In your main app I would recommend always splitting out react, react dom and any react lib components you use into a vendor bundle (webpack) and mark it as external in your main bundle so that you do not unintentionally bundle two versions.
You can have react in either peerDependencies or in dependencies. The difference being that with a peerDependencies, react is only installed once for the package using your package. If you put it in dependencies, react will be installed twice, one time for the package using your package, and once time for your package.
React itself seems to favor peerDependencies for some reason. You obviously don't want two separate versions of react in your Javascript bundle (which happens by default if you use dependencies), but that is easy to fix with npm dedupe.
So there's no correct way to do it, both peerDependencies and dependencies work. Using dependencies is more in line with the node/NPM way, but using peerDependencies is friendlier to users of your package that doesn't know about npm dedupe and why it's needed.

Do all npm packages need an export?

I am new to nodejs packages and what I understood was that to share code you had to do a module.export (in addition to adding a package.json)
For example bootstrap-select does not have an export function but is available on npm.
So my question is do all modules require an export and also can I do a require('bootstrap-select') in my code?
no, all npm modules do not require an export. npm is now being used more generally for not only javascript packages intended for use under node.js but front end code for browsers, CSS libraries, etc. At the very least, an npm package could just deliver a payload of files not even including any javascript, such as some images, some CSS, some HTML, etc.
So you can only do require('some-module') if that package has either an index.js file or has set the main property in it's package.json file properly.
However if you are authoring a javascript module for node.js, then yes you'll need to export something in order for your module to load properly.
No, npm modules do not require doing something with module.exports. If you do not touch that object, requireing your module will return an empty object (since that is the default for module.exports. However, this can be useful if your module is only intended to be required for side effects, rather than a return value.
For example, the module you linked to modifies global state by attaching a jQuery event handler.
As per i know ,
1.All npm modules are not required to build an app.
2.If we use var bootStrap = require('bootstrap-select'); using bootStrap variable you can access bootStrap module.
so we can pass that object in anywhere of your code
3.To install a dependency modules,
In package.json give dependency block as like this
"dependencies": {
"express": "2.3.12",
"jade": "latest",
"redis": "0.6.0"
}
you can change and edit your packages. then enter a command npm install in command prompt it will install only dependency modules.
If i made any mistakes please correct me Thanks.

What is the proper package.json manner to publish a npm package developed with Browserify?

I am publishing a npm package developed with Browserify, and wonder what is the proper manner to construct a package.json.
The package is a node server-client app (it is actually atom package), and the client side is based on Browseriy.
./www/js/index.js -> ./www/js/index.bundled.js
The required modules are marked and highlight.js.
The both modules are used only on the client side code/file which is bundled by blowserfiy.
A lazy and simple solution would be simply, just to have
package.json A
{
......,
"dependencies":
{
...,
...,
"highlight.js": "*",
"marked": "*"
}
}
and to include the www/js/index.bundled.js file in the npm package files as it is after the browserify in my local dev environment.
However, now I think the npm package.json can be one of the below:
package.json B
{
......,
"dependencies":
{
...,
...,
},
"devDependencies":
{
"highlight.js": "*",
"marked": "*",
"browserify": "*"
}
}
In this case, browserified ./www/js/index.bundled.js file is left in the npm package, and treat marked and highlight.js as a devDependencies, and also browserify.
Then
package.json C
{
......,
"dependencies":
{
...,
...,
"highlight.js": "*",
"marked": "*",
"browserify": "*"
},
"scripts": {
"run": "browserify ./www/js/index.js -o ./www/js/index.bundled.js"
}
}
Just let you know, I have never tried this, and don't know this scripts-run actually runs on npm install myPackage, perhaps not, and maybe you know the proper configuration, maybe there's no such a thing.
In this scenario, ./www/js/index.bundled.js is excluded from the npm package file, and built from the latest npm packaged marked and highlight.js.
The reason I think this manner is somewhat proper is especially in the scenario the npm modules are used and shared in both server and client side.
For instance, take a look at dnode. This RPC module is developed by the same author of browserify (#substack), and should share the same version of dnode module in both server and client side. If a pre browserified ./www/js/index.bundled.js is bundled in the published npm package, it will be outdated compared to server side dnode. Sure we may be able to specify the version to install by package.json, but it's better to use the latest on both server and client side.
Any suggestion? Thanks.
I suggest to use second choice and specify browserify as a devDependency.
You have to build it before you publish your package to npm registry, so users won't need to install browserify themselves.
It's also useful to add a Makefile and make as a prepublish script.

Resources