Circular dependency issue while exporting from single file using babel-module-resolver - react-native

I was working on a react native project and while perfoming hot reloading app goes into cyclic recursion resulting in maximum call stack exceeded. More details of this issue can be found here
From here I realised that there is something wrong and circular dependencies are getting created.
I decided to give madge a try and see whats going on in the project. After running the command I saw quite a number of circular dependencies.
Now since my project is quite huge debugging that was quite a task so I created a small version of my project containing a single folder.
I created a utils folder in which I have 4 files: -
utils/index.js
utils/device-helper.js
utils/init.js
index.js
For imports I am using babel-module-resolver
utils/init.js
import {deviceInfo} from "utils";
export const init = () => {
// initialising app and calling backend API with device info
};
utils/device-helper.js
import DeviceInfo from "react-native-device-info";
const API_LEVEL = "v0";
export const deviceInfo = () => {
try {
return Object.assign({}, {
apiLevel: API_LEVEL,
deviceId: DeviceInfo.getUniqueID(),
device: DeviceInfo.getDeviceName(),
model: DeviceInfo.getModel(),
osVersion: DeviceInfo.getSystemVersion(),
product: DeviceInfo.getBrand(),
country: DeviceInfo.getDeviceCountry(),
appVersion: DeviceInfo.getVersion(),
manufacturer: DeviceInfo.getManufacturer(),
userAgent: DeviceInfo.getUserAgent(),
buildNumber: DeviceInfo.getBuildNumber(),
bundleId: DeviceInfo.getBundleId()
});
} catch (e) {
// TODO: Report to Bugsnag
return {};
}
};
utils/index.js
export * from "./init";
export * from "./device-info-helper";
index.js
export * from "./utils";
After running madge command I get following :-
tests-MBP:madge-test harkirat$ madge --circular index.js
Processed 4 files (684ms)
✖ Found 1 circular dependency!
1) utils/index.js > utils/init.js
However, if i change utils/init.js to following it works:-
utils/init.js
import {deviceInfo} from "./device-helpers";
export const init = () => {
// initialising app and calling backend API with device info
};
I am not able to understand the cause of this circular dependency. Can someone please help?
Here is link to the repository.

I don't see a .babelrc in the repo, but here is what I think:
In utils/init.js you import using:
import {deviceInfo} from "utils";
That is same as:
import {deviceInfo} from "./utils/index";
In utils/index.js you do a export * from "./init". This export from basically first imports all the contents of ./utils/init and the reexports it.
So:
utils/init.js imports from ./utils/index
./utils/index.js imports from ./utils/init
There is your circular dependency.

Related

React Native Storybooks Component not Loading

I'm trying to load the default stories that come when you first install Storybook. Had some issues getting the server to start but I managed to fix it by adding port and host in the config. But even after getting it to run, clicking on any of the components doesn't update.
I'm expecting to see a Button.
And ideas? Here's the storybook index.js. I'm using Expo.
// if you use expo remove this line
// import { AppRegistry } from "react-native";
import {
getStorybookUI,
configure,
addDecorator,
} from "#storybook/react-native";
// import { withKnobs } from '#storybook/addon-knobs';
import "./rn-addons";
// enables knobs for all stories
// addDecorator(withKnobs);
// import stories
configure(() => {
require("./stories");
}, module);
const StorybookUIRoot = getStorybookUI({
host: "192.168.100.6", // replace this ip address with your local ip address
port: "7007",
asyncStorage: null,
});
// If you are using React Native vanilla and after installation you don't see your app name here, write it manually.
// If you use Expo you should remove this line.
// AppRegistry.registerComponent("%APP_NAME%", () => StorybookUIRoot);
export default StorybookUIRoot;
Also not sure if this is related but I've had to comment out addon-knobs in addons.js because it can't find it even though I have addon-knobs in my package.json:
import '#storybook/addon-actions/manager';
import '#storybook/addon-links/manager';
// import '#storybook/addon-knobs/manager';
I've tried replacing it with
register
like I've read on here but it still didn't work.
import '#storybook/addon-knobs/register';

Cannot run expo web

I encounter the error 'Cannot access __fbBatchedBridgeConfig on web' when trying to run expo web
The instructions I got according to https://github.com/expo/fyi/blob/main/fb-batched-bridge-config-web.md was to do the following
Remove internal imports
You can remove the import altogether, or you can move an internal import inside of a platform specific block:
import getDevServer from "react-native/Libraries/Core/Devtools/getDevServer";
or
let getDevServer = () => { /* no-op */ }
if (Platform.OS !== 'web') {
getDevServer = require("react-native/Libraries/Core/Devtools/getDevServer");
+ }
However, I'm not sure where to insert this code. I've tried inserting it on my home page, on app.js, and I still encounter this error.
Could anyone help me out on this?
(I'm using EXPO 4.13.0, SDK 43 and react-native 0.64.3)
This error shows when you try to use a nested library from react-native.
Search specifically for react-native/ with your IDE in your project to find where you are importing such nested library.
There you can replace the offending import like:
import example from "react-native/example";
to:
let example = () => { /* no-op */ }
if (Platform.OS !== 'web') {
example= require("react-native/example");
}
You also need to import Platform like:
import { Platform } from 'react-native';
But note other errors might arise if you DO need to use that library, so also edit where you are using it.

Is there a bundler/tool that does not bundle by default, just do specified transforms like compiling SCSS modules?

I want to create a UI library and publish it to NPM. I don't like however the idea of bundling the code into single file and adding bundler code around my code, which is what all bundlers do by default (well, bundler must bundle I guess).
I'm using TypeScript and I build my non-ui packages with tsc. I want to keep that and let bundler or other tool just run through the result and change few things.
For example let's take this file:
import React from "react";
import styles from "./b.module.scss";
const B = () => {
return (
<div className={styles.index}>index</div>
);
};
export { B };
It's getting compiled into this ESM code:
import React from "react";
import styles from "./b.module.scss";
const B = () => {
return (React.createElement("div", { className: styles.index }, "index"));
};
export { B };
//# sourceMappingURL=b.js.map
Not much changes, but this is what I want at this step.
Now I want the tool to:
see the module.scss import
build b.css file, replacing class names with mangled ones
replace import styles from "./b.module.scss"; with import "./b.css";
replace { className: styles.index } with something like: { className: "b_index_f9cb22" } (that reflect new class name in b.css)
and that's basically all
I guess those are the steps normally taken by webpack plugins, but webpack does more than that, like I said - adding its own code, bundling things together, minimizing the code, etc. Some of these things I seem to be able to skip, but still the output is far from my original one.
Is there a tool that allows me to do what I want?

How to integrate inertiaJS with quasar framework?

I would like to integrate intertiaJS into my Quasar app so that I can communicate with my Laravel backend. My problem now is that the general stuff is taken over by the Quasar CLI, which is good in principle, but in this case it takes away my entry point as described at https://inertiajs.com/client-side-setup:
import { createApp, h } from 'vue'
import { App, plugin } from '#inertiajs/inertia-vue3'
const el = document.getElementById('app')
createApp({
render: () => h(App, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: name => require(`./Pages/${name}`).default,
})
}).use(plugin).mount(el)
My thought is that I could use a boot file like the offered in Quasar (https://quasar.dev/quasar-cli/boot-files), but I have to admit that I don't have the right approach.
When I look at the app.js that is automatically generated, I see that nothing special happens in the rendering:
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.conf.js > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import Vue from 'vue'
import './import-quasar.js'
import App from 'app/src/App.vue'
import createStore from 'app/src/store/index'
import createRouter from 'app/src/router/index'
export default async function () {
// create store and router instances
const store = typeof createStore === 'function'
? await createStore({Vue})
: createStore
const router = typeof createRouter === 'function'
? await createRouter({Vue, store})
: createRouter
// make router instance available in store
store.$router = router
// Create the app instantiation Object.
// Here we inject the router, store to all child components,
// making them available everywhere as `this.$router` and `this.$store`.
const app = {
router,
store,
render: h => h(App)
}
app.el = '#q-app'
// expose the app, the router and the store.
// note we are not mounting the app here, since bootstrapping will be
// different depending on whether we are in a browser or on the server.
return {
app,
store,
router
}
}
I.e. in principle I should be able to link in without it causing any conflict situations. The question is, how would that look?
I have to link into the rendering afterwards and overwrite it as described in the code example. I would like to stay with the Quasar Cli, because it is very useful and the situation described here is the only exception.
p7
the boot files is the right place to inject and initialize your own dependencies or just configure some startup code for your application.
I have not had the opportunity to use the library you mention, but I detail a little how you could implement
create your boot file
import { plugin } from '#inertiajs/inertia-vue';
export default async({ app, Vue }) => {
Vue.use(plugin);
}
until there you have 50%. On the other hand, you cannot do a mixin to the main instance but you could do it for each page, however I recommend that you make a component part to which you add the data you need and make a mixin of the library you need
<template>
<div />
</template>
<script>
import { App } from '#inertiajs/inertia-vue';
export default {
mixins: [App],
props: ['initialPage', 'resolveComponent'],
}
</script>
In order to do this, modify according to how the library you use works.

Importing TypeScript Module located in path lower than current path throws Scope Error

In an attempt to put together an AMD-friendly TypeScript application skeleton, I've run into a snag: I can't seem to drop down from my current path to import a module in another directory. I can import modules that are above, but below throws an error:
TypeScript Error: The name ''../core/View'' does not exist in the current scope
Here the is the structure of my (very basic) app:
app/
- core/
- View.ts
- views/
- HomeView.ts
- Application.ts
In my Application.ts file, I can successfully import a module like so:
import HomeView = module( 'views/HomeView' );
export class Application {
constructor() {
console.log( 'initializing Application' );
}
}
Which, when using the --module AMD flag, correctly outputs
define(["require", "exports", 'views/HomeView'], function(require, exports, __HomeView__) {
var HomeView = __HomeView__;
var Application = (function () {
function Application() {
console.log('initializing Application', HomeView);
}
return Application;
})();
exports.Application = Application;
})
Now, the problem is when I jump into views/HomeView.js and attempt to import my core/View BaseClass to extend from:
import View = module('../core/View');
export class HomeView {
constructor() {
console.log('Hello HomeView!');
}
}
Which throws this complete error:
TypeScript Error: The name ''../core/View'' does not exist in the current scope
File: test/src/app/views/HomeView.ts
Start: 21, Length: 14
Line: import View = module('../core/View');
---------------------------^^^^^^^^^^^^^^--
Is this a bug in the compiler, or is my understanding of module imports faulty? Why would i be able to import views/HomeView, but not ../core/View?
Any help would be greatly appreciated.
I managed to get this to work using a root path - although I can't tell you why your relative path doesn't work.
import view = module("./app/core/View");