Flow+Webstorm "Cannot resolve module" - node.js

I have an existing project where we integrated Flow's type system into the react side. The project is electron-based so, by definition, a mono-repo. We ran in to all kinds of issues getting flow to recognize import statements.
node_modules imports would fail:
import _ from 'lodash'; // Flow: Cannot resolve module lodash
And more importantly, we wanted absolute pathing relative to our project:
import {MyComponent} from 'src/component/myComponent';
// Flow: Cannot resolve module src...
Finding a solution on this took a bit of digging, and the documentation is a little lacking in some areas, so I want to throw a compiled list of what actually worked out there.

TL;DR;
Get flow set up on webstorm so it is giving you module errors
Set up flow globally, and point webstorm's js settings to use Flow and point it at the global copy of flow-bin (not even the exe, just the dir)
add the following options to .flowconfig:
[options]
module.name_mapper='^src\/\(.*\)$' -> '<PROJECT_ROOT>/src/\1'
module.system=haste
Full version
A few basic steps have to be done to get flow to work in webstorm at all:
Install flow-bin globally
Several sources made the claim that flow-bin runs better globally
Install flow-bin globally
yarn global add flow-bin
or
npm i -g flow-bin
Double check that it gave you a current version of flow-bin, this
refused to work on 0.75.0 or earlier
Set up Webstorm's flow executable
On Webstorm: File > Settings > Languages & Frameworks > Javascript
Choose Flow as the JavaScript language version
Find where your package manager (yarn or npm) stores global files
On Windows+yarn this is C:/Users/[your username]/AppData/Local/Yarn/Cache/v1
On Windows+NPM this is C:/Users/fish/AppData/Roaming/npm/node_modules
That makes my flow path:
C:/Users/[your username]/AppData/Local/Yarn/Cache/v1/npm-flow-bin-[whatever]/
On Webstorm's JavaScript settings, Target the Flow package or executable to the global flow path we just found
Apply, ok
Setting up Flow's .flowconfig
.flowconfig setup side notes
I have a root git project with 2 parts, react, and electron. Flow does things based on where you put the .flowconfig file.
If it includes "all=true", remove that line and go add // #Flow to your files you want flow to check (otherwise it will start indexing all of node_modules
Reproducing my problem
Put .flowconfig in your react directory
Enjoy all the "Flow: Cannot import module" squiggly lines of doom
Solution to the module problem
This is my current .flowconfig
[ignore]
.*/build/.*
[include]
[libs]
[lints]
[options]
module.name_mapper='^src\/\(.*\)$' -> '<PROJECT_ROOT>/src/\1'
module.system=haste
[strict]
Why does this work?
Tells the name mapper to resolve modules that begin with src/ to the src/ directory so your absolute paths to your project's files work:
module.name_mapper='^src\/\(.*\)$' -> '<PROJECT_ROOT>/src/\1'
Tells flow to use the "haste" module system:
module.system=haste
The haste module system step is important because otherwise it doesn't know that by 'lodash' you mean './node_modules/lodash'. Telling it to use haste means it will properly find your import statements. More info on haste available here

Related

How to import from a bundle created in webpack?

I'm working on a project that's based on a given sample project that uses a package named Seeso.
The sample project uses the 'cross-env' and 'parcel-bundler' packages which are both deprecated, and I would like to replace them with pure node.
I managed to create a backend that statically serves requested files and thus handles imports,
but the Seeso package seems to dynamically resolve its imports using a webpack bundle (I have little to no knowledge of webpack but not even a configuration file is present; just the bundle), and I get the following error after I changed the import path of Seeso in the easy-seeso.js file to its actual path:
Uncaught SyntaxError: The requested module '/external_modules/seeso/dist/seeso.js' does not provide an export named 'CalibrationAccuracyCriteria' (at easy-seeso.js:2:34)
because of
import Seeso, {InitializationErrorType, CalibrationAccuracyCriteria} from '/external_modules/seeso/dist/seeso.js';
How can I import the needed Seeso files from the webpack bundle with minimum work and understanding of webpack as possible? (Preferably without running webpack commands before running - would like to run 'node server.js' and that's it)
Here is the sample project:
https://github.com/visualcamp/seeso-sample-web

More issues with TypeScript modules

... yep. It's that time of year again. TypeScript is wonderful, except for the mess that is the module system. Presently, I'm struggling with a scenario where I'm dealing with two separate repositories / projects (what ever you wanna call it). I've got a library and a program using said library. I'm using Node's subpath exports feature in the package.json to indicate multiple submodules within the library. From the NodeJS (and the bundler's perspective) this is fine, but not in TypeScript's world. TypeScript is adamant that none of the modules exist.
Here's a quick summary of the library
/utils
package.json
tsconfig.json
build automatically generated build directory
iter.js
iterSync.js
...
lib autogenerated declarations files
iter.d.ts
iterSync.d.ts
...
src source files
iter.ts
iter_sync.ts
...
lib manually written definitions files
iter.d.ts
iterSync.d.ts
It's package.json has an exports field which defines a list of exports and their respective declaration file.
library/package.json
...
"exports": {
"./iter": "build/iter.js",
"./iterSync": "build/iterSync.js",
...
}
...
I've tried various alterations of the above, such as
Node16 module resolution strategy
Adding a types property to each export
Using the main and typings fields in library/package.json
Adding "lib" to the includes of library/tsconfig.json
Upgrading to TypeScript 4.6.4
Restarting the TS Language Server through the VSCode command menu
Basically all permutations of the above
How I use the library
I don't think it makes a difference, but I'm referencing the module through a pnpm link dependency statement for development, and a git://... url for production:
program/package.json
...
"dependencies": {
"jcake-utils": "link:../library", // dev
"jcake-utils": "github:J-Cake/jcake-utils", // prod
...
}
Regardless of what I do, TypeScript refuses to locate my submodules in the program
...
import Iter, * as iter from 'jcake-utils/iter';
import IterSync, * as iterSync from 'jcake-utils/iterSync';
...
$ pnpm exec tsc -v
Version 4.6.4
$ pnpm exec tsc -p program/tsconfig.json
src/build.ts:2:29 - error TS2307: Cannot find module 'jcake-utils/iter' or its corresponding type declarations.
... (A bajillion errors saying exactly the same thing, just across different files)
I alluded to this being a common issue (because from my experience it is) but I would greatly appreciate some very specific feedback as to how I can correct this issue and/or if I should potentially restructure either program or library, and how best to do so. I've been unable to find documentation that is helpful in my situation, as many of the suggestions given by the TypeScript community have not worked.
Thanks kindly

Node package dependencies on IBM Cloud Foundry - require/module is not defined (Package not loading)

I am working on an application via the toolchain tool on IBM Cloud and editing the code via the Eclipse Orion IDE. As I am not accessing this through my local cli, my understanding is that in order to so call npm install {package}, I would just need to include the package in the package.json file under dependencies and require it in my app. However, when I load the application, I get the require is not defined indicating that the package has not been installed. Moreover, the require() is being used in the app.js file with the application being launched but not from files in my public directory.
After playing around further, it seems it might have to do with the way the directory tree is being traced as the error is only thrown in subdirectories. For example, require('express') works in app.js which is in the main directory ./ but fails when it is called in test.js in ./subdirectory/test.js. I feel like I'm missing something painfully simple like configuration of endpoint or something.
I've been searching around but I can't seem to find how to get the packages loaded, preferably without using the cli. Appreciate any pointers. Thanks!
Update: After playing around further, I am also getting module is not defined error when trying to require from another file in the same directory. For example module.exports = 'str' returns this error. While trying to require('./file') returns the require is not defined. It might have to do with how node is wrapping the functions?
Update 2: Tried "start": "npm install && node app.js" in package.json but no luck. Adding a build stage which calls npm install before deployment also does not work
Update 3: After adding npm install build stage, I am able to see that the dependencies have been successfully built via the logs. However, the require is not defined error still persists.
Update 4: Trying npm install from my CLI doesn't work as well even though all packages and dependencies are present
Update 5: Running cf restage or configuring cache via cacheDirectories does not work as well
Opened a related question regarding deployment here
Found out my confusion was caused due to me not realizing that require() cannot be used on the client side unless via tools such as Browserify.

Can I use bare imports for my local modules using native es6 modules (mjs)?

Background:
Assuming my folder structure is something like:
project/
-- package.json
-- index.mjs
-- lib/
-- config/
-- index.mjs
When I used require() natively in node I could reference a local module using a bare import like:
const x = require('config')
because I added the root of my library folder to the NODE_PATH environment variable. (assuming of course when I was using cjs/require the extension would have been .js)
The problem:
When I try to do that using native es6 modules (mjs) like:
import x from 'config'
I get the error:
Error [ERR_MODULE_RESOLUTION_LEGACY]: config not found by import in [SOME_ABS_PATH]/index.mjs. Legacy behavior in require() would have found it at [SOME_ABS_PATH]/lib/config/index.mjs
The question:
Anyone know how to solve this? Or what the future is for dealing with relative paths for local module resolution within the node native es6 module system?
Research so far:
Only resource I've found on this so far is from here http://2ality.com/2017/09/native-esm-node.html stating:
Path resolution works slightly differently: ESM does not support NODE_PATH and require.extensions. And its specifiers always being URLs also leads to a few minor differences.
And on the error message below ERR_MODULE_RESOLUTION_LEGACY - google showed up literally nothing.
Okay, so a colleague (thanks #robin-balmforth ) gave me the answer:
From https://nodejs.org/api/esm.html#esm_no_node_path it says:
Notable differences between import and require No NODE_PATH NODE_PATH
is not part of resolving import specifiers. Please use symlinks if
this behavior is desired.
And from something even more canonical:
https://github.com/bmeck/node-eps/blob/es6-module/002-es6-modules.md#521-removal-of-non-local-dependencies says:
All of the following will not be supported by the import statement:
$NODE_PATH $HOME/.node_modules $HOME/.node_libraries $PREFIX/lib/node
Use local dependencies, and symbolic links as needed.
So instead of me setting the NODE_PATH environment variable I have to setup a symlink like:
ln -s ../lib node_modules/lib
Seems to work fine yay.
We suppose the reason is for compatibility with the browser implementation of es6 modules?
There is some discussion on the reasoning behind this change from https://github.com/bmeck in this node-eps issue https://github.com/nodejs/node-eps/issues/11 like:
The solution is not a workaround, it is how path resolution works.
Having a single flat namespace for "bare" path resolution is
important.

Unable to import native nodejs module in electron project

I'm working on an open source electron project which I am building using webpack. One requirement for my project is to use the nodegit library which has to be built as a native module.
I've followed what appears to be conventional advice when working with native modules and electron. That is, I run electron-rebuild, have configured the source package to use and finally have configured node-loader to catch the import of any .node files.
Unfortunately, when I go to include the module, I end up with this error:
ERROR in ./node_modules/nodegit/dist/nodegit.js
Module not found: Error: Can't resolve '../build/Debug/nodegit.node' in
'C:\Users\atrauzzi\Development\atrauzzi\gerty\node_modules\nodegit\dist'
# ./node_modules/nodegit/dist/nodegit.js 18:11-49
# ./src/Layer/Domain/Thunktor/Git/CloneGitRepository.ts
# ./src/Layer/Gerty/Component/Repository/AddGitHubRepository.tsx
# ./src/Layer/Gerty/Component/Repository/AddRepository.tsx
# ./src/Layer/Gerty/Component/Workspace.tsx
# ./src/Layer/Gerty/Component/App.tsx
# ./src/Layer/Gerty/GertyServiceProvider.ts
# ./src/Bundle/GertyElectron.ts
The only thing I can see that's suspicious at this point is that when I rebuild the module to work with electron, I only get a Release directory, when the import seems to be looking for Debug:
This could be a red herring however as nodegit is written to try Debug as a fallback after Release has failed.
The general ask here is "How do I get this native module working in my project?".
I also have a corresponding question over at the repo, although on the off chance that my issue is unrelated to the library itself, or that there are some battle-worn veterans of native modules in electron, I figured SO would be a good place to check as well.
Try configuring your webpack by specifying the native module as an external dependancy rather than load it using the node-loader.
https://webpack.js.org/configuration/externals/

Resources