Install different version of npm packages in package.json conditionally - javascript

I'm developing a web app which uses a private package.
In some circumstances, I rather to use the local version of the package or different version of that package.
Is there any solution to indicate to use different version of package in package.json?
i.e:
npm install --local
while my package.json looks like:
...
"dependencies": {
...
"my_package": if(local) "address_to_local_package/" else "5.6.1"
...
}

npm does not accommodate this (and honestly, probably should not). This seems like the type of thing that is usually handled at runtime via the NODE_ENV environment variable or similar mechanism. The module changes behavior depending on whether NODE_ENV is set to "production" or "development". (But that's just convention. You can use values like "local" if you want.) So rather than installing different versions of the module, there's a single version that behaves differently based on the value of that environment variable.
If you really want different code bases installed entirely, it will take some effort but you can write a postinstall script for npm to run. Your module then becomes nothing more than a script and then the postinstall figures out what to actually install based on environment variables or maybe a command line flag. This seems brittle to me, though. I'd think hard about if you're solving the right problem here if you go this route. NODE_ENV seems more elegant and conventional.

Related

Must i specify dependencies in package json file

I just recently heard of the package.json file but all my small projects have always worked without it.
I've installed many npm modules globally and always use var x = require("express");"just for example" without even initializing the package.json and putting express as a dependency.
Is it really important
First of all, I strongly doubt require("express") will work out of the box without having the express package installed in your project's node_modules folder, but just globally. There are ways to accomplish this, though.
But even if you accomplished to require packages from the global installation folder, what happens if you have multiple packages requiring different versions of the same package? There may be breaking changes between major versions of packages. So if you install a new version of package xy globally, older projects of yours expecting a different version of package xy may stop working.
On just your local machine, you can achieve all that, still without a package.json though.
The main purpose of the package.json comes clear, when you want to share your project with other people. Aside from some basic information (like a package name and some description), it will also list the dependencies which need to be installed for the project to be runable. While the necessary dependencies may exist on your machine, how will you make sure, they are also installed on a different machine without having them listed somewhere? And the place for listing the dependencies of a package is -- surprise surprise --- the package.json file ...
They are global, not in your project so when you do the deploy, you will must have to install all global for each server.
Yuu can install packages-cli global, but project dependencies ( also dev on dev dependencies) is better have its own package.json so you can deploy.
Also if you share your project, how someone will know what packages is needed.
The better is to have for each project its own package.json on its root folder, even if you always use the same libs.

What is the difference between installing eslint as extension and installing as npm package?

I have been following various blogs and videos on setting up and configuring eslint and prettier for vscode and development. But every article fails to explain why do we need to separately install eslint as an npm package and vs code extension?
what difference it will make if I install either of the ones?
why do we need to separately install eslint as npm package and vscode extension?
Short answer: you don't.
Long answer:
Installing ESLint/Prettier as extension, allows you to format/check your code inside the VSCode.
However, installing them also as dependencies brings extra benefits:
VSCode will use exact same package as installed. So you will not spot the situation when VSCode says OK, but your CI server says: NOT OK
You will get control over the versions, and can update whenever you want
You will be able to use different versions for different projects. This is especially important, when you can't migrate old project, but want to use the latest possibilities for the new one
You will be able to access Prettier/ESlint through the script block of the package.json, and be able to write custom commands with parameters exactly as you need
You will be able to pair them with Husky or NPM hooks to automatically verify/format the code
From my experience, if you can install something locally - install it as package dependency (except CLI like create-react-app or angular-cli that helps you start the app). This will make your life a bit predictable.
These programs can format your code (ESLint and Prettier) and detect specific syntax (ESLint).
When installed as an extension in your IDE (vscode for example), you can get:
squiggly lines in real time;
and format-on-save.
But someone who starts up your project on their own environment might not have these extensions installed (might not even have the same IDE) and thus might not get these.
When installed as npm packages (and included somewhere in the pipeline, either in the npm start, or in your continuous deployment, or...)
you won't get real time squiggly lines,
but you can still get auto-formatting (though not necessarily on save, depending on the configuration),
you can get blocking rules (meaning instead of just seeing errors / warnings, you can actually block the pipelines until the dev fixes said errors / warnings)
you can insure anyone who starts the project, from any IDE, gets the packages included

Workflow to use a sub-module typescript written module into a non-typescript module?

I'm having a private typescript module that is a dependency of another major project. This dependency is achieved by having the typescript repository as sub-module and installed using npm to the local sub-folder. The typescript module can compile into JavaScript on its dist folder and by doing so the major module that consumes it can make use of it without issues. But here is my problem, the dist folder isn't committed to the typescript repository.
What should be the workflow to follow in order to consume this typescript module from a JavaScript-only major project? The best I can think at this moment is to instruct someone, or something, to run the $ tsc command before using the major project but it's "annoying" since it isn't a transparent step. If this is a weird approach, what would be a more ideal approach? Thanks everyone.
You have a couple of options.
Assuming you're not planning to have a private npm registry using e.g. Verdaccio you can simply commit the dist folder. This is definitely the simplest option and it's not completely unheard of, I'd probably go with that option.
This solution is actually quite unusual, but it's pretty clever and it works. You could add a postinstall script in package.json of your TypeScript package that would run tsc after installing the package. The downside is that you'd have to add typescript as your dependency, which is not ideal (it should generally be a dev dependency, in which case it wouldn't be installed in the project using the package), but for some it might not be a big deal at all.
Instead of installing the package, you could use npm link and then have a script in your main project that would compile it. You'd have to run it every time something changes in that package, though. You could also append it to your npm start script, so it runs before it, e.g. "start": "npm compile-package && webpack" (assuming your current start script is "start": "webpack"). It doesn't scale very well though.
If your Javascript project uses Babel (and I'd assume so considering you said it's a "major" project) you could change its config so it transpiles Typescript for you using #babel/plugin-transform-typescript, however it can be a bit complicated, IIRC e.g. projects created with create-react-app by default don't recompile the code from node_modules.
There are probably more solutions, but I'd probably go with 1 or 2.

Configuring globally installed eslint

I installed globally eslint#4.2.0 and wanted to use some predefined configs. When I tried to install eslint-config-google it said that I don't have eslint>=4.1.0 (which I had of course, but installed globaly). The same problem occured when installing eslint-config-airbnb-base - ultimately predefined configs can't see globally installed eslint (and even eslint --init can't see it cause it installed another instance of eslint locally when I run it). Then I decided to install both eslint and configuration files locally, in my projects directory - works like a charm, but still I'd like to have these things in global scope so I wouldn't have to care about it each time I make a new directory for my projects.
Is it possible to make eslint and predifined configs work at global scope or at least have global eslint and local configuration file?
ultimately predefined configs can't see globally installed eslint
Actually, they can. Or rather, global ESLint can use global configs. It just doesn't know how to cross the barrier between global and local.
Then I decided to install both eslint and configuration files locally, in my projects directory - works like a charm
Good choice. This is going to be crucial when you eventually have projects with conflicting needs.
but still I'd like to have these things in global scope so I wouldn't have to care about it each time I make a new directory for my projects
That is what project scaffolding tools like Yeoman are for. Here is the one I use, generator-seth.
Whenever I start a new project, I simply type seth and answer a couple of questions and it's done with glorious magic under the hood.
Is it possible to make eslint and predifined configs work at global scope or at least have global eslint and local configuration file?
Yepp. You can have a local .eslintrc file and the global ESLint will respect it. You can run eslint --init to set this up (that will also install ESLint locally, but you don't need to use it).
But an even better way is to use XO, which is built on top of ESLint (and supports all ESLint rules). Unlike ESLint, XO knows how to automatically choose the appropriate installation to use. You can install it both locally and globally and its global CLI will defer to the local copy when one is detected. This is important because it means that each project can keep its own version of the linter while still allowing you to run XO globally. So if a breaking change comes out, your projects are not screwed all at once or broken when they have conflicting needs. The configuration for XO is kept locally either way, so unlike ESLint you do not have duplicate local and global configs.
I have recently encountered the same issue, here is my solution (OS: Windows):
First, I run eslint initial command to configure my preference:
$ eslint --init
? How would you like to use ESLint? To check syntax, find problems, and enforce code style
? What type of modules does your project use? CommonJS (require/exports)
? Which framework does your project use? None of these
? Where does your code run? Browser, Node
? How would you like to define a style for your project? Use a popular style guide
? Which style guide do you want to follow? Airbnb (https://github.com/airbnb/javascript)
? What format do you want your config file to be in? JavaScript
Checking peerDependencies of eslint-config-airbnb-base#latest
The config that you've selected requires the following dependencies:
eslint-config-airbnb-base#latest eslint#^4.19.1 || ^5.3.0 eslint-plugin-import#^2.17.2
? Would you like to install them now with npm? No
Second, I copy the ".eslintrc.js" file that eslint generated locally into my user home directory (C:\Users\username) to make it a global configuration file.
Finally, I use npm to install the required packages globally:
npm install -g eslint#^5.16.0 eslint-config-airbnb-base eslint-plugin-import
*Important*
Don't use npm install -g eslint because it will install the latest eslint version
(like 6.0.1) and therefore, the dependencies of eslint-config-airbnb-base and eslint-plugin-import will go wrong
And here is the article you may find more information if you want configure differently How to globally set up eslint in vscode.

Node package priority, global vs local

I've noticed that I have Angular 2 installed globally, and I don't know when I might have done that, or if that's the way it's supposed to be. It doesn't seem like that would be necessary if it's defined in every project.
It makes me wonder what side effects that have if I had different versions locally and globally. Which one takes priority? What's the best way to remove all of the Angular packages.
Globally installed NPM packages really only impact your command-line environment. Things like pm2 or sequelize insert bin/ stubs into the PATH to make your life easier.
In order to require something it needs to be present in package.json as well as properly installed.

Categories