require() resolution in React Native - node.js

I'm trying to find out why require('foo/bar.png') works differently in two RN projects
In one project, foo is registered as root via metro.config.js
extraNodeModules: {
foo: path.join(__dirname, 'src/foo'),
}
In another project, foo lives in under app_root/node_modules
so foo is at app_root/node_modules/foo
So in both projects, I can do import something from 'foo/something'
But when it comes to require, two projects behave differently..
There is a line in foo/components/hello.js
require('foo/assets/image.png')
In the first project, the image file is correctly found,
But second project complains that it can't find with an error /path/to/root_project/node_modules/foo/component/node_modules/foo/assets/image.png
It seems as if require is assuming that where the require is called should be the project root or something.
Where should I look for or how do I debug this?
Can I print module.paths in ReactNative project ?

is path is same for both project ? If in first project require() works then it should be work on second project, one reason for not working that your path is not correct in second project. Therefore check it again.

Require is not a React statement - it is Node.js statement, use import instead.

Related

How can you set an entry point to a folder in a node package?

I work on a component library and a React app that makes use of that component library. My component library looks like this when I build it:
/core
/components
/MyComponent
/utils
/hooks
This means when we import a component, it looks like this:
import '#our-package/core/components/MyComponent/MyComponent';
Is there a way we can make the components folder our entry point? The utils and hooks folders should not be accessible. Ideally, we could use:
import `#our-package/core/MyComponent/MyComponent`
I'm reading about the node main property you can use in package.json but it doesn't look like it works with folders. Is there another way to do this?
You could move your folder upwards, in the same directory as your package.json.
If you're targeting a newer version of Node.js, you can also make use of the new packages structure. You can basically say exactly where #our-package/core/subpath points at in your #our-package/core package. It has a whole system behind it that should allow you to export whole directories at certain subpaths.

NodeJS import file with the same name as a folder

I have the following file structure: ([] are folders)
[MySQL]
ConnectionPool.ts
Connection.ts
MySQL.ts
In my code, I am using typescript to develop the app, which will be built to javascript for the production version. The development version is tested directly from the uncompiled typescript files, using babel with the following configurations:
{
"presets": [
["#babel/preset-env", {
"targets": {
"node": "current"
}
}],
"#babel/preset-typescript"
],
"plugins": [
"#babel/plugin-transform-runtime",
[
"module-resolver",
{
"alias": {
... list of some aliases
}
}
]
]
}
My problem is the following, I do most of my imports like this:
import ConnectionPool from 'MySQL/ConnectionPool`
which works for me, as when I run my dev code, the compiler correctly identifies the file extension to .ts, and it also correctly identifies the built versions file extension to .js.
But if I want to import my MySQL.ts file, I can't do it this way, as I will get the following error: Error: Cannot find module './'. If I specify in my import statement the file extension, everything works correctly, but then, when I build my code, there will be no more .ts files in there, so I will get errors there.
Strangely, on the frontend, where I use webpack, I get no complaints about importing files without extension whose name is the same as a folders name in the same directory. What solutions do I have for this issue, which does not revolve around renaming my files or folders in the structure?
Rename your file MySQL.ts to index.ts and move it into the folder MySQL
In the meantime, I resolved my problem by explicitly specifying .ts as the file extension, and when building the code, using the babel-plugin-transform-rename-import to replace the .ts extensions to .js extension.
I won't accept this as the correct answer, as this is too hacky for me, so if a better solution comes up, I am still open for it.
I don't believe what you want to do is possible, node will automatically include either the file or the directory but if both of them are called the same thing node will have no idea which one to import and it will always prefer one over the other.
Using import Example from 'example' will have node search either for any files called example.js or directories called example with an index.js and it will only load one of them.
The reason webpack does it correctly is because webpack will never bundle a "directory", it will take what you've specified as an import and try all of the resolves extensions until it finds one and then it will import that file, so you'll never have conflicting files with directories with webpack.
I thought maybe a solution is to use aliasing in your typescript config so that you can use import Example from '#example' and differentiate between your directories and files that way. Then you can also do import Example from 'example' if you just want to load the file itself. But even then I don't think that will even work because once it gets compiled to javascript you'll just have the same issue as before with conflicting paths.
That being said, while I understand being a little bit obsessed with naming conventions and small things, I really don't think you should be storing "mysql" outside of the "mysql" directory, for two reasons. The first reason is that it's part of that directory, that's what that directory is for, it contains the "mysql" stuff, so why would you want to store it outside. Secondly using a "index.ts" communicates something to other developers, when I open up a new project or directory I'm immediately looking for something called "index.ts" or similar, otherwise I have no idea where to even begin. Using "index.ts" is a good way to communicate to anyone that "this file right here is the one you're looking for, everything starts here". That being said, just call it index.ts and store it where it belongs.
You can try in your tsconfig.json to set moduleResolution to the classic strategy:
{
"compilerOptions": {
"moduleResolution": "classic"
}
}
Unfortunately, looking at the code, this seems to be impossible in your setup:
import is handled by module-resolver
module-resolver calls the NPM package resolve
resolve.sync checks for the no-extension case before testing extensions.
Given that most systems are going to follow Node module resolution, I think you're out of luck, without some manual aliases or moving files around.
FWIW, NodeJS says that extensions in import are mandatory.

Jest changed test directory resulting beforeAll is not defined

I used to put all my tests together inside of __test__ directory. But I decided to put each test files into each component's directory with different name convention.
Old Structure:
src/
__test__/
example.test.js
example2.test.js
New Structure:
src/
components/
example/
example-controller.js
example-model.js
example-route.js
example-test.js
As naming and location of a directory changed, I updated all import statement and namings for according files. I was using default feature of Jest but since I changed test file name to example-test from example.test I also updated package.json
"jest": {
"testRegex": "./src/components/*/.*.-test.js$"
},
Problem is when I run the project, npm run it throws
beforeAll((0, _asyncToGenerator3.default)( /#PURE/_regenerator2.default.mark(function _callee() {
ReferenceError: beforeAll is not defined
any idea why it is happening?
Try regextester with your file-paths before getting frustrated. Also, look at some popular existing javascript projects using jest and check their jest configurations to see how the community is settling on project structure. It may seem simple to follow others, but most software engineers don't work alone, and usually agree on good practices.
Consider coming back to this project in a year; You are changing the default behavior of a simple process that works beautifully out of the box. Someone may hate you later after a git blame.
If all you want to do is check all -test.js files, slowly modify the default config until you match the file paths you want.
(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$
Should probably (for you) be:
(.*/src/.*(-test).jsx?)

Intellij IDEA resolve local require() path [ node.js ]

I'm trying to avoid relative require() calls in my express setup. I'd also like to avoid placing my code in the node_modules folder. In short, I'm trying to implement any of the methods described in this gist.
Any of those solutions will work fine for executing code with node or npm. However, I'm trying to find a solution that will also be supported by Intellij IDEA's code resolver, i.e. trying to make sure "go to declaration" and autocomplete hinting works.
I've tried the following
Setting NODE_PATH in the run configuration.
Using a global prefix, i.e. require( global.__base + "mylib").
Adding a symlinked folder to node_modules/.
Adding a symlink from a lib/ folder to node_modules/lib/ does work, but comes with two caveats:
Changes to the source files aren't picked up automatically, so I have to manually "synchronize" node_modules/lib, and
When "going to declaration", IntelliJ (of course) opens node_modules/lib/mylib instead of lib/mylib. This can lead to confusion as the actual file and the symlinked file can be open in separate windows.
Instead of a different way to require local paths (all these methods do work with node after all), I'd be happy with a way to hint to IDEA that it should search the lib/ folder for sources.
So, I realised that if you add a library through Project Structure > Libraries, it won't actually be enabled.
Instead, go to Preferences > Languages & Frameworks > Javascript > Libraries and add a new library. Set the framework type to node_modules, Visibility to Project and add your lib folder.
After adding it, make sure the Enabled checkbox is checked.
That's it, Intellij can now resolve your require('mylib') paths.
Use whatever method from the gist mentioned in the question to actually get node to resolve the paths.

Spurious module ".." in Android Studio project

I followed the steps in How to share a single library source across multiple projects to add an external library to a project.
My project(s) structure:
Project MyTest1:
Module MyLib
Project MyTest2:
Module MyApp
I edited settings.gradle in MyTest2 and added , ..:MyTest1:MyLib to the include directive. Now, I am able to see and use the external library project from within MyTest2 project. Things work as expected.
However, I see a spurious module ".." alongside MyApp and MyLib. There are no nodes under it and it doesn't seem to cause any problems. I am wondering what exactly is this module for and if there is a way to get rid of it. Regards.
Edit
Both my projects are under a directory C:\MyDev. It appears that, anytime you bring up MyTest2 project, AS modifies a file MyTest2.idea\modules.xml and inserts the following line:
<module fileurl="file://C:/MyDev.iml" filepath="C:/MyDev.iml" />
It then complains that the module was not loaded and creates a fake ".." module. I think this is the root of the problem.
Do not declare ..:MyTest1:MyLib as your include. It will cause many problems. Instead, declare it the following way:
include ':MyLib'
project(':MyLib').projectDir = new File('../MyTest1/MyLib')

Resources