react-native how to import project root directory? - react-native

App
|-- application
|-- config
| |-- themes.js
| |-- redux.js
+-- views
| |-- login
| | |-- login.js
|-- index.js
index.js
....
import themes from './config/themes';
import themes from './config/redux';
...
login.js
....
import themes from '../../config/themes';
import themes from '../../config/redux';
...
I hope it like this:
....
import themes from '#root/application/config/themes';
import themes from '#root/application/config/redux';
import ... from '#root/...';
...
if methods of php
$root = 'User/React-Native-Project/';
include $root.'/application/config/themes.php';
This can improve the development efficiency and avoid the wrong path and other issues.my english is not good.

Alias in React Native
There is a point where you will have multiple files and folder in your project. And we need to get the reference of one file from another in any random possibilities. If we are following the relative path such as
import themes from '../../config/themes';
then it’s really very hard for us to get an idea where it takes by the symbol ‘../ ‘ and in more complex project this is a night mare.
In this post we will find the possible solution and alternative on this type of scenario. Let’s take an example project with following folder structure.
Your App Root Directory
|-- app
|-- component
| |-- login
| | |-- login.js
+-- resources
| |-- icon
| | |-- userupload.png
|-- index.ios.js
|-- index.android.js
We have two possible solution to point each node in the above folder structure.
Use #providesModule (update: will not work for RN versions 56 and above. https://github.com/facebook/react-native/issues/21152)
A secondary solution that would work but is less “safe”, is to use #providesModule in your file. This comes with less boilerplate but since it’s based on Facebook’s own internal use case, it could change based on their internal whim. You can read more about it here:https://github.com/facebook/fbjs
To use it you need to include this comment at the top of your file:
/**
* #providesModule login
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
export default class login extends Component{
render(){
return(
<View>
<Text> this is login page
</Text>
</View>
);
}
}
Then you can import it the same as above:
import themes from 'login';
Use babel-plugin-module-alias
A babel plugin to rewrite (map, alias, resolve) directories as different directories during the Babel process. It’s particularly useful when you have files you don’t want to use with relative paths (especially in big projects).
Uses:
Install babel cli
npm install --g babel-cli
Install babel-plugin-module-alias.
$ npm install --save babel babel-plugin-module-alias
Create a file .babelrc in root directory or add a key babel: your project’s package.json and add following lines of code.
"babel":{
"plugins": [[
"module-alias", [
{ "src": "./app", "expose": "app" },
{ "src": "./app/resources/icon", "expose": "icon" }
]
]]
}
and finally clear the cache and restart the node server
npm start -- --reset-cache
Full source code can be downloaded from here

use babel-plugin-module-alias
npm install --save babel babel-plugin-module-alias
create a .babelrc file for project root directory.
{
"presets": [
"react-native"
],
"plugins": [
["babel-plugin-module-alias", [
{ "src": "./application", "expose": "app" }
]]
]
}
start command:
npm start -- --reset-cache
Now we can do the:
....
import themes from 'app/config/themes';
import themes from 'app/config/redux';
import ... from 'app/...';
...

Use babel-plugin-module-resolver.
The existing answers were long-winded, outdated and made it way more complicated than it needs to be. I felt obligated to add a succinct answer to help others.
Install the package:
npm install --save-dev --save-exact babel-plugin-module-resolver
Modify or create a .babelrc file in your root directory with the following:
{
"plugins": [
[ "module-resolver", { "root": ["./"] } ]
]
}
You can change ./ to the root of your code, like ./application or something.
Update your import paths:
Instead of writing:
import themes from '../../config/themes';
You can write this:
import themes from 'config/themes';
Profit!

You can create a package.json file containing {"name": "root"} in your root folder. Note that this may be a different file than the original 'package.json' that every project has.
And in case you want to use another folder named X populate the package.json with {"name": "X"}. so now you can simply use import foo from 'X/foo' in your project.
For more information check these:
https://github.com/facebook/react-native/issues/3099#issuecomment-221815006
https://medium.com/#davidjwoody/how-to-use-absolute-paths-in-react-native-6b06ae3f65d1

I see 2 solutions to accomplish what you want:
1) Create a "themes" package
One thing that's nice about the React Native packager is that it will pick up any "packages" (or "node modules") that are anywhere in your project directory structure.
This means that in your config directory, you could have a themes directory with a package.json (with a "name" field of 'themes') and an index.js (the index.js would contain the code that you now have in 'application/config/themes'.)
Then, when you want to import this code you can simply do:
import themes from 'themes';
Remember, you can place this "package" anywhere you want in your directory structure. While this isn't "exactly" what you were looking for, it is definitely a working solution.
2) Use #providesModule(update: will not work for RN versions 56 and above. https://github.com/facebook/react-native/issues/21152)
A secondary solution that would work but is less "safe", is to use #providesModule in your file. This comes with less boilerplate but since it's based on Facebook's own internal use case, it could change based on their internal whim. You can read more about it here: https://github.com/facebook/fbjs
To use it you need to include this comment at the top of your file:
/**
* #providesModule themes
*/
Then you can import it the same as above:
import themes from 'themes';
Here is an example of it being used in the React Native project itself: https://github.com/facebook/react-native/blob/master/Libraries/Text/Text.js#L9

This actually isn't really about React Native. I think that it's more of a Babel question. The answer is actually quite simple—use the Module Resolver package. This allows one to configure a module-specifier-to-URL resolver for use by Babel. It's especially useful for avoiding relative URLs.
First, execute the following command:
$ npm install --save-dev babel-plugin-module-resolver
Then, in your ".babelrc" file or in a babel attribute of your project's "package.json" file, specify the options for the plugin:
"plugins": [[
"module-resolver", {
"root": ["./application"]
}
]]
Finally, clear the cache and restart the node server
$ npm start -- --reset-cache

To use the babel plugin, you need the babel-preset-react-native :
Add babel-preset-react-native:
$ npm i --save-dev babel-preset-react-native babel-plugin-module-alias
Add .babelrc
```
{
"presets": ["react-native"],
"plugins": [
["module-alias", [
{ "src": "./app", "expose": "app" }
]]
]
}
```
react-native run-ios
See:
https://www.npmjs.com/package/babel-preset-react-native
https://github.com/tleunen/babel-plugin-module-alias

Related

astro-i18next Tfunction showing keys instead of translation

I use t() function to translate text.
The function is acting like there are no locales in astros /public folder.
My file structure
My translation.json file for en:
{
"index": {
"testHeader": "Test Header"
}
}
Here is my index page code:
---
import Layout from "../layouts/Layout.astro";
import { t, changeLanguage } from "i18next";
changeLanguage("en");
---
<Layout>
<h1>{t("index.testHeader")}</h1>
</Layout>
My astro-i18next.config.mts:
/** #type {import('astro-i18next').AstroI18nextConfig} */
export default {
defaultLocale: "en",
locales: ["en", "cs"],
};
My astro.config.mjs:
import { defineConfig } from 'astro/config';
import astroI18next from "astro-i18next";
import tailwind from '#astrojs/tailwind';
// https://astro.build/config
import react from "#astrojs/react";
// https://astro.build/config
export default defineConfig({
integrations: [astroI18next(), react(), tailwind({
config: './tailwind.config.cjs',
})]
});
the t() function shows the passed key instead of translation.
I runned npx astro-i18next generate which did nothing
I had a similar issue; I fixed it with a config change and a downgrade.
(since it's still in beta, gotta keep an eye on that)
NOTE: The current version of "astro-i18next" is "1.0.0-beta.17".
Add the following to your astro-i18next.config.*: baseLanguage: "en"
Downgrade your version to 1.0.0-beta.13, between versions 10 to 17 only this one worked for me.
Good but not Necessary: add this to your package.json scripts: "i18n": "npx astro-i18next generate"
Run this command and should be successful: pnpm i && pnpm run i18n && pnpm run build
Considering this fix, I'm looking forward for similar issues to be resolved in stable release; However, for the time being this should get you going.
I fixed it using npm update.
For some reason my app's dependencies weren't updated.

pnpm, workspace dependency and also supporting publishing?

I am new to pnpm workspaces and am trying to resolve the following issue.
My demo project:
root
packages
common-ui
main-lib
common-ui is a Vite based package containing some Vue components that can be reused by other packages, in my example it's being used by main-lib.
"dependencies": {
"ui-common": "workspace:*"
},
common-ui is referencing an index.ts inside its package.json
"main": "index.ts",
index.ts is exporting my Vue components:
...
export { default as Heading } from './components/Heading/Heading.vue';
...
Now I am able to import those components inside main-lib:
import { Heading } from 'common-ui'
This all works fine but I would also like to be able to publish my library to the npm registry. As common-ui is using the Vite, it's possible to build in library mode: https://vitejs.dev/guide/build.html#library-mode. My package inside common-ui will need to change to:
{
"name": "common-ui",
"files": ["dist"],
"main": "./dist/common-ui.umd.js",
"module": "./dist/common-ui.es.js",
"exports": {
".": {
"import": "./dist/common-ui.es.js",
"require": "./dist/common-ui.umd.js"
}
}
}
main is not referencing index.ts anymore but a dist folder that only gets updated when the vite command is ran. Is there a way for me to support both publishing/versioning and referencing the actual source code from inside main-lib?
I've taken a quick look at Rush.js but I am not sure if provides a solution and I want to be sure before I continue on that path.

Vue: icons are not displayed when css.extract: false

When building a Vue library (component), according to Vue docs, you can set css.extract: false in vue.config.js to avoid the users having to import the CSS manually when they import the library into an app:
vue.config.js
module.exports = {
css: {
extract: false
}
}
However, when you do that, the icons are not displayed in the production build.
In this case I'm using #mdi/font and weather-icons. Neither of them load:
To reproduce
You can reproduce this with this Vue library (component):
Create new Vue project with vue create test
Clone the repo and put in the same directory as the Vue test project
In vue-open-weather-widget set css.extract: false in vue.config.js;
And comment out CSS import:
import 'vue-open-weather-widget/dist/vue-open-weather-widget.css'
Build vue-open-weather-widget with yarn build
Import it into the test Vue app with yarn add "../vue-open-weather-widget";
Serve the test app yarn serve
I have looked at your lib (nice component BTW). I created a build with css: { extract: false } and first looked at the behavior when importing vue-open-weather-widget.umd.js directly into an HTML file. And that worked without any problems.
The thing is that the fonts remain external in the dist after the build. And it seems that there is a problem to find the fonts when your component is loaded in a Webpack project (in our case Vue CLI project). I don't know why the fonts are not referenced correctly. But I have found another, and possibly a better solution.
As it is stated in the MDI docs, the use of the web fonts can negatively affect the page performance. When importing only one icon, all of them are imported, which in turn increases the bundle size. In such a small component this is more than suboptimal, especially for the component users. Therefore here is the alternative solution, also suggested by MDI:
Use #mdi/js instead of #mdi/font
Remove all #mdi/font references in your code and install deps:
npm install #mdi/js #jamescoyle/vue-icon
Replace all icons with SVG(e.g. in MainView.vue). Note that on this way only icons are included in the bundle that are used in your components:
...
<span #click="state.settings.view = 'settings'">
<svg-icon type="mdi" :path="mdiCogOutline"></svg-icon>
</span>
...
import SvgIcon from '#jamescoyle/vue-icon'
import { mdiCogOutline } from '#mdi/js'
...
components: {
SvgIcon
},
data () {
return {
mdiCogOutline: mdiCogOutline
}
},
Adjust vue.config.js:
module.exports = {
css: {
extract: false
}
}
Build component:
# i would also include --formats umd-min
vue-cli-service build --target lib --formats umd-min --name vue-open-weather-widget src/main.js
Now your dist contains only 192.68 KiB vue-open-weather-widget.umd.min.js and the component is ready to use over CDN or in a Vue CLI Project, without importing any CSS or fonts. I have tested both cases. Here is how it looks like:
Hope it helps you! Feel free to ask if you have further questions.

How to force .vue extension in all imports using eslint?

In VS Code with Vetur (the extension for working with Vue), "Go to definition" will not work on component imports where there's no .vue extension at the end (Vetur FAQ link)
I was wondering if there's an eslint rule that will force the user to always provide an extension when using an import statement in .vue files?
Examples:
✔️ This works:
import HelloWorld from '#/components/HelloWorld.vue'
Right clicking on HelloWorld and pressing Go to definition in VS Code wil take you to the HelloWorld.vue file.
❌ This doesn't:
import HelloWorld from '#/components/HelloWorld'
If you press Go to definition on HelloWorld (leftmost), VS Code will just move the cursor to the HelloWorld you just right clicked. Intended behavior is that we move to the HelloWorld.vue file.
It's easy to do this for paths like ./src/components/A.vue. It's trickier for #/components/A.vue because you need to resolve the # alias.
The below solution works for both.
To force .vue extensions in paths, do this:
1. Install eslint-plugin-import, which extends functionality of eslint by linting import paths. Also install with a custom path resolver - eslint-import-resolver-alias for it:
npm install eslint-plugin-import eslint-import-resolver-alias --save-dev
2. Then, in your ESLint config file (.eslintrc.js, or eslintConfig field in package.json etc), add this:
// I'm using .eslintrc.js
module.exports = {
//...unimportant properties like root, env, extends, parserOptions etc
plugins: ["import"],
settings: {
"import/resolver": {
alias: {
map: [
["#", "./src"], //default # -> ./src alias in Vue, it exists even if vue.config.js is not present
/*
*... add your own webpack aliases if you have them in vue.config.js/other webpack config file
* if you forget to add them, eslint-plugin-import will not throw linting error in .vue imports that contain the webpack alias you forgot to add
*/
],
extensions: [".vue", ".json", ".js"]
}
}
}
}
Here's a repository with a working demo that implements forcing .vue path in imports correctly.
And a screenshot from VSCode and output from npm run lint:
You need to configure eslint-plugin-import to set force on vue files, just add this rule in eslint config
"import/extensions": ["error", "ignorePackages", { "vue": "always" }],

Stencil and Sass file

I am trying to port a React component to Stencil.
The component .scss file has an #import for another A.scss file. That A.scss file #import the bootstrap-sass/assets/stylesheet/bootstrap/_variables and #import another B.scss file.
Can Stencil handle that or do I need to merge everything in one file?
You can import other Sass files; you don't need to merge everything to one single file.
You can keep using Sass as you are using it with React. Just keep in mind that to be able to use Sass with Stencil, you have to install the Sass plugin and add the plugin to the plugins array in your stencil.config.js file.
For more information, check the Sass documentation on the Stencil website.
In your stencil.config.ts (or stencil.config.js) file:
export const config: Config = {
plugins: [
sass({
includePaths: [path.resolve(__dirname, 'path/to/styles')]
})
]
};
Yes, it can handle Sass files and their imports.
Install package stencil/sass:
npm i #stencil/sass -D
In your stencil.config.ts file:
import { Config } from "#stencil/core";
import { sass } from "#stencil/sass";
export const config: Config = {
// ... You configuration
plugins: [
sass({
includePaths: ["./node_modules/"],
}),
],
};
In the above example, we're telling the Stencil compiler to compile Sass files. The includePaths array tells the compiler the directories/files it should look into for the Sass files.
In order to use #import from a Node.js package, all you need is:
#import "~bootstrap-sass/assets/stylesheet/bootstrap/_variables";
Note: The ~ operator here is necessary when not importing using relative paths(./style.scss, ../../style.scss, etc.)
If you are importing the b.scss file using relative paths (./b.scss, ../b.scss, etc.), you won't need to add anything else to Sass plugin configuration.
I never tried multiple imports, but I can't see why this wouldn't work.
To get Stencil working with .scss, you should install this plugin, as described here.
npm install #stencil/sass --save-dev
Then add this property to config in file stencil.config.ts.
plugins: [
sass()
]