I am looking for a convenient way to access files in the root of my application while avoiding require() strings that look like:
require('../../../../myModule')
There are some good solutions out there for Node (https://gist.github.com/branneman/8048520) but I haven't seen a way to use global variables in React Native.
Does anyone have a clean solution to this problem?
From Marc Shilling's answer on https://github.com/facebook/react-native/issues/3099
You can use an absolute path on imports/requires:
import {ProximaNovaText} from 'MyApp/src/components';
require('MyApp/src/utils/moment-twitter');
where 'MyApp' is whatever name you registered in your index.ios.js file
Note for VS Code: This works, but be warned that you might lose intellisense and cmd/ctrl + click. Thanks Johan for the info about CS code
You can mark a directory as a package by adding a package.json within the root directory you want to resolve.
e.g:
- app
- package.json // ← Add this package.json file
- config
- components
- ... (etc)
package.json should look like this:
{ "name": "app" }
Restart your packager
react-native start --reset-cache
Now you can use the following in all of you project files:
import store from 'app/config/store';
import Button from 'app/components/Button';
You can use this same method across other directories in your project, I don't think this works via require, although image paths seemed work.
As noted in the comments, you may lose auto-complete in your editor (VSCode).
For Jetbrains IDE's there are some ongoing tickets here:
https://youtrack.jetbrains.com/issue/WEB-17254
https://youtrack.jetbrains.com/issue/WEB-20104#comment=27-1486526
https://intellij-support.jetbrains.com/hc/en-us/community/posts/205434510-Configure-custom-modules-resolve-folder
This might help with Jetbrains IDE's in the meantime.
// A slash may allow auto-complete to work in your IDE (but will fail to resolve)
import Button from '/app/components/Button'; // Cannot be resolved
Put code below on top of your myModule file:
/**
* #providesModule myModule
*/
Then you can use require('myModule') in any other files.
Complementing #Tiagojdferreira
You can use his solution with babel-plugin-module-resolver library.
Install with:
npm install --save-dev babel-plugin-module-resolver
Configure .babelrc adding plugins property like this:
{
"presets": ["react-native"],
"plugins": [
["module-resolver", {
"alias": {
"#src": "MyApp/src",
"#otherAlias": "MyApp/src/other/path",
}
}]
]
}
Usage:
require('#src/utils/moment-twitter');
Hope this helps!
You can use global variables in react native, same as node, properties defined on global are accessible globally.
e.g.
global.foo = "blah";
console.log(foo); //logs "blah"
Most of the node solutions in the gist above should work correctly.
One I've used in the past is defining a global function at the top directory level, usually on the first line like
global.rootRequire = function(path) { return require(path); }
Which simply allows deeply nested requires to be from the root, and avoids all of the ../../ business.
However the other comment is true, if this is really an issue, there is probably something structurally deficient with the project.
Related
I have a plain old NodeJS project (with Typescript) and I'm really struggling to find out how to do ES6 imports for local files without having to do "../../../foo/bar" all the time.
There are loads of similar questions but all seem to revolve around babel/Webpack which I'm not using.
If I do the following:
import foo from `/bar`
it looks for it in the root folder of my PC (e.g. c:/bar) and fails.
I have tried using a .env file with NODE_PATH set to various hings ("/", "." etc) but no luck. I have also tried setting "type: 'module'" in my package.json and my tsconfig.json file has {"baseUrl": "."}
So I think I've tried every answer I can find. Am I just doing them in the wrong combination or is the solution something different?
Here are two tricks I've used for this, with Node.js and native ES modules.
file: dependencies
If you want to access <project root>/bar from a sub package two levels down, adding this to the package.json dependencies:
"#local/bar": "file:../../bar",
..makes bar available to the said subpackage as #local/bar.
While relative paths are still present, they are now all in the package.json files and the sources never need to know..
Use dynamic import()
Pick the root folder's path to a constant and do this:
const foo = await import(`${rootPath}/bar`);
This was pretty simple to implement for me, using Typescript in VSCode.
In tsconfig.json, I added "baseUrl": "./", under compilerOptions
After a restart of VSCode, VSCode will automatically import using psuedo-absolute paths.
The paths won't begin with /, that still points to your drive root.
If the is below the current file, it will still use a ./relative/path, but no more ../../tree/traversing
Then I set dev in packages.json to
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "cross-env NODE_PATH=./ nodemon ./app.ts"
},
I use cross-env. You may use the set command and nodemon for automatic reloading of change files.
Setting NODE_PATH to ./ tells NodeJS to do what Visual Studio and TypeScript are doing.
I do have package.json in my src directory. You may not, and may need to change some pathing to adjust.
I am not sure what you mean by "local files without having to do "../../../foo/bar""
Let me explain how Javascript handles imports. Here is a basic folder structure.
C:Users/NAME/Project/randomfolder/bar.js
- Project
- Random Folder
- foo.js
- bar.js
Option 1 Probably the better option for 95% of what you will do
Let's say you are trying to import foo.js into bar.js we first get our current location of bar.js using a . so it would be
import foo from "./Random Folder/foo.js"
If you are going the other way the . is still used to say get current location in the folder structure but you pass a second . so .. then a / to go up a folder. So to import bar.js into foo.js it would look like this:
import bar from "../bar.js"
We are going up a folder then looking for the file we want.
Option 2
But if you know you folder structure is going to be very big and you will be importing always a few folders up or down why not make a variable and then use string literals.
let folder = `../../../`
import test from `${folder}foo`
You have a few options of how to handle what you want to do.
Option 3 For NodeJS and modules
If you are using NodeJS and want to get the path not relative, the use the app-root-path module. It lets you always get your project root and then dig into to files accordingly. This can be accomplished with string literals.
var appRoot = require('app-root-path');
import foo from appRoot + "/foo/bar/folders/bla/bla"
or
import foo from `${appRoot}/foo/bar/folders/bla/bla` <-- string literals
I want to use babel-plugin-react-css-modules to create unique class names, so I did a PoC: I ejected create-ract-app, then I add babel-plugin-react-css-modules to plugins in package.json:
"babel": {
"presets": [
"react-app"
],
"plugins": [
"babel-plugin-react-css-modules"
]
},
When I start application I see that class in HTML is set correctly, but inside <style> tag it's regular .App name:
Am I missing something? I think it should be pretty easy to set up and I make some stupid mistake I can't see. Thank you in advance for every answer.
Edit: App.js code:
import React from 'react';
import './App.css';
function App() {
return (
<div styleName="App">
Test app
</div>
);
}
export default App;
Rant: One of the many reasons I'm against the create-react-app (CRA) is because of how inflexible it can be when it comes to customization. If you're looking to include features, I'd recommend creating your own webpack configuration. Why? You'll become more familiar with Webpack, how to configure it, how to work within its limits, and how to add/change/adjust packages to your needs.
That said, the CRA comes preconfigured with both global and local (module) CSS imports and it conflicts with babel-plugin-react-css-modules (BPRCM). The CRA expects .css files without module.css to be normal global imports. Meanwhile, BPRCM expects .css files to be local imports. Not only is that a conflict, but the localIdentNames are mismatched. By default, CRA looks for App.module.css where module.css specifies it's a modulated import, like so: import { App } from "./App.module.css";. As such it assigns localIdentNames as [file/folder]_[local]_[hash] as mentioned here, here and within an ejected config/webpack.config.js (Lines 432-456 -- it utilizes the react-dev-utils/getCSSModuleLocalIdent package).
In order to resolve these conflicts, you'll need to establish a localIdentName (by default BPCRM uses this generateScopedName: [path]___[name]__[local]___[hash:base64:5] (4th option in the table), so I'll be using it for my example below), then you'll need to add BPRCM to the webpack.config.js under babel-loader because the CRA doesn't look for a babel configuration, then you'll have to remove the CSS module imports rule, and lastly, you'll need to add some options to their global CSS rule to make it local and utilize the localIdentName.
Here's a working example: https://github.com/mattcarlotta/cra-css-modules
To utilize the repo above:
open a terminal window on the ~/Desktop and clone the repo: git clone git#github.com:mattcarlotta/cra-css-modules.git
cd into the cra-css-modules folder and type yarn install or npm install
type yarn start or npm start to run the example
What I changed:
Declared a localIdentName to match BPRCM's default scoped class name (you can change this name to whatever you like and it'll still work with the example repo above).
Added BPRCM to the babel-loader rule.
Added a modules configuration to switch the global CSS rule to a local CSS rule
Removed the local modules CSS rule.
Changed all classNames to styleName in the App.js file.
We're using Tabulator-tables in a large Angular project and I cannot seem to find a usable definition files.
I've tried https://www.npmjs.com/package/#types/tabulator-tables which seems updated etc but it results in lots of errors in my IDE and the project will not compile as a result. There are many errors even though the compilation worked before I added the types package. Its pointless and impractical to add many #ts-ignore comments.
Be advised - I took notice to use the same version of the type definition package as installed in my project (v4.2.2). I assume the problem is with the automatic generation of the above package - the resulting .d.ts file is not usable as a result.
Please correct me if I'm wrong and any help in integrating definition files will be appreciated. TIA!
I had a similar issue with adding TypeScript typings on Angular project and here's what i did:
encapsulated Tabulator inside Angular component (data-grid.component.ts in my case);
npm install #types/tabulator-tables
created file data-grid.component.d.ts with:
declare module 'tabulator-tables' {
export = Tabulator;
}
the key thing: removed import Tabulator from 'tabulator-tables' from file data-grid.component.ts
And it's worked.
A full set of TypeScript Typings can be found in the #types/tabulator-tables npm package
npm install #types/tabulator-tables
An example of how to use the typings in a project can be found here
The Language Documentation includes more information on the available typings
I already wrote an answer for this issue, not good enough in my opinion, but some people upvoted it as right, so I decided to leave it as it is and write a new one.
There is some issues with adding types for tabulator, this is because type annotations not being exported, but there is a way to use them.
After installation of types for tabulator (npm install --save #types/tabulator-tables), you should open (or create it, if it's not exists) file index.d.ts inside directory src, and copy following code into it:
declare module 'tabulator-tables' {
export = Tabulator;
}
You need to ensure that you have "allowSyntheticDefaultImports": true inside compilerOptions of file tsconfig.json or tsconfig.app.json (depends on your project), and tsconfig.spec.ts (it needs for unit testing).
Very important to unload and start over ng serve after editing of tsconfig.
After that all typings should work. Just in case I created simple Angular example, hope this helps.
What is the proper workflow to include the library to angular 4.0 and use it inside a component?
My steps:
yarn add mathjs
Then there should be a way to injects js libraries in one of the build lifecycles so the angular4 component can use it. JHipster utilizes Webpack and Yarn.
Then I tried to add to Component (docs):
import { mathjs } from "./mathjs";
and
var math = require('mathjs');
Those were not working. What am I missing?
UPDATE:
It seems like mathjs uses older approach suggesting var math = require('mathjs'). Maybe it is similar to JQuery question in some way...
UPDATE2
This is a great question and I'm glad you ask because I wish I had what I'm about to write the first time I encountered this little problem. This is a typescript/javascript and webpack issue before it is an angular issue. I definitely am planning a writeup on my blog soon as possible.
Your Scenario:
You run
npm install mathjs
Now you try to use math.js from a component:
Find math.js dist js file (node_modules/mathjs/dist/math.js) and reference like this
import {mathjs} from "../../node_modules/mathjs/dist/math";
But you get error message saying "set --allowJS". You do that like this:
Set --allowJS in config (tsconfig.json)
{ "compilerOptions": {
"allowJs": true, ...
Now you get:
ERROR in ../node_modules/mathjs/dist/math.js (12209,13): Unreachable
code detected.
Looking in the math.js source, you see that it is an old school module but there is no root wrapper function (one function to bring them all and in the darkness bind them..) (more on that later).
Solution: install a typings file for the target lib (#types/mathjs)
First, check to see if you can get #typings files for your module here
https://microsoft.github.io/TypeSearch/
Grab mathjs typings file from npm (https://www.npmjs.com/package/#types/mathjs) and Run npm install to add the typings .d.ts files to the target lib's node_modules directory
npm install --save #types/mathjs
Add your type ref correctly
import * as mjs from "mathjs"
Use it like this:
console.log("e was: " + mjs.e);
I have the complete solution for the math.js lib on my github here
https://github.com/res63661/importOldJSDemoWithTypings/
More:
For examples look no further than your own angular project. CLI creates node_modules folder each time you run npm install after creating a new project with ng new . Dig down into here and note the d.ts files for many of the .js files.
When messing with typings or defining your own (.d.ts files) be sure to restart your server between builds as the typings don't seem to update currently on the fly
Further reading:
http://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html
https://angular.io/guide/typescript-configuration#typescript-typings
https://microsoft.github.io/TypeSearch/
Lastly:
If you are in a pinch and this is not working for you, I did have success creating a custom wrapper for a different (much smaller) module by wrapping it in a master export type
export var moduleNamer = (function(){
//module implementation
}());
then dumping the .js file local to my component and then referencing it as follows:
//reference like this from your component:
import {moduleNamer} from "./source"; //from source.js
--rich
I did this way and it worked for angular9.
First install npm package mathjs.
npm install mathjs
Then import in your component or directive.
import { round } from 'mathjs'
You may test with this.
console.log(round(math.pi, 3) )
Try to include the script into index.html:
<script src="./assets/math.js" type="text/javascript"></script>
Then add this into your component file:
declare const math;
You can then use math in your component:
ngOnInit(): void {
console.log(math.sqrt(-4););
}
I am new to aurelia, and I need create a prototype project of the framework. At the beginning, I planed to use skeleton-typescript-aspnetcore skeleton, but when I tried the vs2017rc, I found it uses .csproj as the default format(while vs2015 is project.json/.xproj), I think we should follow the vs2017 because we will upgrade our IDE after it's been launched.
The vs2017 have a wizard to upgrade .xproj project, but after the upgrading(skeleton-typescript-aspnetcore), there still lots of error ahead me...
I also tried aurelia-cli, but seems it has not support vs2017 yet, does anyone could give a guide to create the prototype project? I will integrate some plugins like the skeleton mentioned above, such as gulp,karma,breeze...
thank you in advance.
Since Visual Studio 2017 just launched I thought I'd answer how I solved this, as there are still many errors when using "skeleton-typescript-aspnetcore".
Using https://github.com/aurelia/skeleton-navigation/releases/tag/1.1.2 as a starting point, these are the steps to get it running:
When you first run the project you will get errors complaining that some files located in /test/ is not under 'rootDir'. In your tsconfig.json the rootDir is defined as "src/", this can be solved simply by moving your test folder inside your src folder. This will cause new errors because the paths defined in those files has now changed. You will need to edit app, child-router and users imports like this:
import {Users} from '../../users'; IntelliSense should help you out here.
The command gulp test will also not run before changing to the new path, you can change the path in karma.conf.js:
files: [
'src/test/unit/setup.ts',
'src/test/unit/*.ts'
],
Next the file users.ts will throw errors like Type 'Response' is not assignable to type 'any[]'. You will need to tell TypeScript what you're declaring like this: public users : Object = []; or simply: public users = {};
The final problem is that you're going to have a lot of duplicate identifier errors, at the time of writing this the cause of this seems to be from the changes brought on by TypeScript version 2.2.1. I don't know what specifically breaks, but I know that previous version 2.1.5 still works. So what you need to do is to run npm install typescript#2.1.5 --save in your src/skeleton directory, the --save is just to update your package.json file, you can do this on your own later as well if you wish.
After you've done that your gulp errors (20~ of them) should be resolved. But there are still some errors remaining caused by duplicate signatures. Again, things have changed in TypeScript 2.0+, there is now a simplified way of getting and using declaration files. Here is an answer on SO on how to use the #types feature: How should I use #types with TypeScript 2 , but to keep this short and sweet you will have to go to your tsconfig.json file and explicitly tell where to find the #types/node folder. It would look something like this:
"compilerOptions": {
...
"typeRoots": [
"node_modules/#types"
],
"types": [ "node" ]
...
},
Hope this helps, with these changes the project should now build and launch correctly.
EDIT:
I recently ran into some problems again with building my project. I got a lot of duplicate identifiers again... I however ran across this answer on SO: TypeScript throws multiple duplicate identifiers
Apparently TypeScript latest ships with fetch definitions out of the box, so I was able to run the command from the answer in the link:
npm uninstall #types/whatwg-fetch
And upgrading from typescript 2.1.5 to latest:
npm install typescript --save
You might even want to install typescript globally by appending -g.
Also this will continue to be an issue unless you comment out/delete url and whatwg-fetch from typings.json globalDependencies in order to prevent it from recreating itself:
"globalDependencies": {
//"url": "github:aurelia/fetch-client/doc/url.d.ts#bbe0777ef710d889a05759a65fa2c9c3865fc618",
//"whatwg-fetch": "registry:dt/whatwg-fetch#0.0.0+20160524142046"
}
Then you can either delete the typings folder, running typings install again or edit index.d.ts in the typings folder and delete the reference paths to whatwg-fetch and url.
Hope this helps someone who might've encountered the same problems even after "fixing" it.