Closed gaearon closed 8 years ago
Does the NODE_PATH=src/
solution work for react-native?
Adding NODE_PATH=src/
in .env
works great! Thanks!
Just to add on this: In case you run your own ESLint config on top you can to add
settings: {
'import/resolver': {
node: {
paths: [path.resolve(__dirname, './src')],
},
},
},
to your .eslintrc
so absolute paths get resolved correctly by linter plugins.
@will-stone's solution of adding NODE_PATH=src/
to .env
works for import {something}
statements, but not for @import {something}.scss
statements for SASS.
You can use the --include-path option in the cli for that
For some reason, my .env
file with NODE_PATH=src/
is ignored. When I run npm start
, I get module not found errors to my components. But if I run NODE_PATH=src/ && npm start
, I get it working. Any ideas?
Yeah, I noticed this too. I solved it with cross-env
:
npm install --save cross-env
Then in package.json
:
...
"scripts": {
"start": "cross-env NODE_PATH=src/ react-scripts start",
...
Hope this helps.
It’s a bug in 1.0.0. See https://github.com/facebookincubator/create-react-app/issues/2225 for updates.
I am somewhat late to this discussion but I'd like to support @FFX01 suggestion, which is, more or less, what I use. Please stop forcing developers to an arbitrarý folder structure. Placing things into src/node-modules
or any other place, for that matter, is not a good idea.
I currently use WebPack's resolve.alias
to create virtual folders for components, store, utils, jest utils. I have adopted a leading underscore instead of @FFX01 's at-sign, but any symbol would do, whatever makes sure that your virtual folders would never collide with an existing package. By using resolve.alias
This is a sample of imports I have in my code:
import isPlainClick from '_utils/isPlainClick';
import { selSector, selUsername } from '_store/selectors';
import { logout, ensureUser } from '_store/actions';
import Menu from '_components/menu';
import Login from '_components/login';
Where is _utils
actually located? Actually, you don't need to know. Nor are you forced to keep it in a fixed position under src
, as it would happen if the only absolute directory reference is src
. Nor are you forced to tinker with other tools that regularly ignore node_modules
.
Besides, using resolve.alias
instead of the Webpack's DefinePlugin
you restrict the use to a particular problem (which is the one we want solved) and prevent abuse.
For example, just like we have a .env
file we could have a .alias
file containing a simple object literal. This is why I used an underscore instead of any other symbol, as it still makes for a valid JS identifier and spares us from quoting the property names:
{
_utils: './utils',
_components: './components',
// ....
}
All relative folder references would be solved relative src/
which should be recommended (and not forced, please).
Thanks and sorry for my lateness.
The reason I personally don't rely on Webpack resolve.alias
for that is that only Webpack would know where the modules are, whereas other tools (like tests, coverage, analysis, documentation, or the code editor Intellisense) wouldn't automatically know where they are.
@cecilemuller
In testing, I use jest.mock
to replace dependencies, for example:
jest.mock('_store/selectors.js', () => ({
configSelectors: {
get: jest.fn((state, name) => state.config[name]),
},
}));
In this case I am mocking an import with a mock function, but with an .alias
file it would be possible to automate the creation of a moduleNameMapper
(http://facebook.github.io/jest/docs/en/configuration.html#modulenamemapper-object-string-string) configuration for jest tests.
I have no solution for editors, except praying for a plugin, eventually.
I'm using babel-plugin-module-resolver in a RN project and it works well with absolute paths. Also it requires just minimum configuration. If i'm not wrong all it does is replacing the absolute paths for theirs relative counterparts in compile time. I'm not sure if it's considered "magic" or if it breaks the node resolution mechanism (I'm new in this) but I hope it is helpful.
Sorry for my bad english.
We’re going to keep supporting NODE_PATH=src
as described in earlier comments.
This is enough to keep this issue at bay for now.
We might revisit this later.
For those using react-scripts-ts
:
NODE_PATH=src/
to the .env
file (thanks will-stone!)"baseUrl": "./src"
to your tsconfig.json
file.Using the above accepted solution I still can't achieve the following:
import { componentA, componentB } from 'components'
instead I still have to do the following:
import componentA from 'components/componentA/componentA'
import componentB from 'components/componentB/componentB'
My component structure is the following:
src
components
componentA
componentA.js
componentB
componentB.js
index.js
@jasan-s as support questions probably belong on StackOverflow, can you paste your question there and include the contents of your index.js file?
@jasan-s I think that should work if the contents of your 'components/index' is correct ...
Haven't tried it out with import, only with require, but if your index.js successfully imports the components from the subpaths and then exports them again using a "{}" then I don't see why it wouldn't work?
Maybe it's the difference between import and require ...
@leob I get an error using it with import.
index.js file looks as follows:
export componentA from './componentA/componentA
export componentB from './componentB/componentB
I'll try stack overflow, see if i can get some help there as well.
@jasan-s try
export {default as componentA} from './componentA/componentA'
export {default as componentB} from './componentB/componentB'
that works :) thanks @will-stone
Wow, {default as ...} syntax that's new for me ... like I said I tried it with require only.
Don't know about you guys but I much prefer using babel-plugin-root-import
:
// .babelrc
{
"presets": [
"react-app"
],
"plugins": [
"babel-plugin-transform-es2015-modules-commonjs",
["babel-plugin-root-import", {
"rootPathSuffix": "src/"
}]
]
}
In any component you can import like so:
// From
import someFile from '../../../../utils/someFile';
// To
import someFile from '~/utils/someFIle';
The ~
acts as your project src/
path. Much cleaner imo, not had any issues with it.
@Ehesp I didn't think it was possible to use babel plugins with an un-ejected CRA, if that's the case then this wouldn't be a solution users could add, but maybe something that could be considered by the CRA team to be put directly in to react-scripts? Is it cross platform compatible?
@will-stone Ah yes sorry this is an ejected app!
Having checked out VueJS for a while, I'm all in favour of using the "@" prefix to denote the src
dir.
I was able to use paths from src
folder without dots by adding
NODE_PATH = node_modules:src
to .env
file. Cheap and fast solution.
@alexeyraspopov is there technically any benefit to using
NODE_ENV = node_modules:src
over
NODE_PATH=src/
?
My bad, I apologize, it should be NODE_PATH
of course. Edited my comment above.
I think the question still remains: do we need to add node_modules
to the path, or is this done regardless and we can just specify src
?
A quick test shows that you can just set NODE_PATH = src
.
Was just about to comment that lol. It does break VSCode's cmd+click feature, but I'm fine with that for shorter imports.
The issue with symlinking node_modules
is that babel will skip transpiling these files by default.
@Vanuan One alternative is to create a folder, say src/vRoots
and put all the symlinks into that folder. Since it is not under node_modules
Babel will compile its contents. Then you add that folder to NODE_PATH
.
As a convention, I started all the symlinks with an underscore, which is otherwise forbidden in NPM so there would be no conflict with npm packages, and it made it clear to the developer that those were virtual folders, not dependencies that could be found in node_modules
.
The advantage was that it was meant to test several architectures so I could swap various alternatives by changing the folders the symlinks pointed to, for example, my _connector
symlink could point to a regular HTTP client, a WebSockets one or even Firebase. Likewise, on the server side, my _db
symlink could point to MySql or MongoDb
Since this folder with the symlinks is along the other source files, exclude it from linting, testing or any other utilities that my browse the folders, otherwise you might get in a loop.
I still can't make this work properly. I have in NODE_PATH=src/
in .env
. However, some imports still fail.
This fails:
// Home.jsx
import { Link } from './Links'
This works:
// Home.jsx
import { Link } from './../atoms/Links'
Folder structure:
src/
app/
atoms/
Links.jsx
pages/
Home.jsx
main.jsx
assets/
@alexdevero setting NODE_PATH=src/
would like nable you to import from absolute base path like so in home.jsx
. import Link from 'app/atoms/Links'
@alexdevero setting NODE_PATH=src/
would enable you to import from absolute base path like so in home.jsx
. import Link from 'app/atoms/Links'
That worked. Thank you very much @jasan-s.
Is it somehow possible, without ejecting, to enable import { Link } from './Links'
or import { Link } from 'Links'
?
We’ve been using Lerna in Create React App, and I really like its approach. I think we should support a similar workflow (even without Lerna itself) for the “absolute paths” feature.
I imagine it working like this:
src
, you can create a special top-level folder calledpackages
.packages
, you can create folders likeapp
,stuff
,lol
, and they all “see” each other so you can import things fromapp/whatever.js
orlol/wow.js
. You can also import any packages fromsrc
(but not vice versa). The entry point is stillsrc/index.js
.npm start
,npm test
, ornpm run build
, we will run a utility that creates symlinks fromnode_modules
of the root project to every folder inpackages
. It reports a hard error if there is a conflict. This means the authors can add server rendering after ejecting without scratching their heads, and that all the tooling assuming Node resolution mechanism keeps working.Am I missing why this would be a bad idea?