Determine javascript framework based on importation - javascript

I am writing a python script that determine the type of javascript framework used in file, I am having issue in detecting when whether the code is node.js file or react.js file. I tried detecting via importation , so far when I have import React from 'react'; I know directly it is react file , but the problem is when we don't have react importation but the file is part of react project ( for eg file contain reducer, hooks) and I have have othe importation, my idea is to to check whether that importation is react , the problem is even if I check npm registry it don't give me info about whether the package is for node.js apps or for react or other. For example this code ,how can I determine whetehr it is node or react or other ?
import { GraphQLScalarType } from 'graphql';
import { Kind } from 'graphql/language';
const LowercaseString = new GraphQLScalarType({
name: 'LowercaseString',
description: 'Returns all strings in lower case',
parseValue(value) {
return value.toLowerCase();
},
serialize(value) {
return value.toLowerCase();
},
parseLiteral(ast) {
if (ast.kind === Kind.STRING) {
return ast.value.toLowerCase();
}
return null;
},
});
export default LowercaseString;

Related

Why is dynamic importing of dayjs not working in typescript?

I am working on a web screen inside a .NET app and I am trying to send date time preference from the system to the web screen using CefSharp settings and setting
AcceptLanguageList = CultureInfo.CurrentUICulture.Name
In my typescript code I want to use dayjs and import dynamically 'dayjs/locale/${language}' where language comes from AcceptLanguageList above.
import React, { useState } from 'react';
import dayjs, { Dayjs } from 'dayjs';
import localeData from 'dayjs/plugin/localeData';
dayjs.extend(localeData);
var lang = navigator.languages != null ? navigator.languages[0] : navigator.language;
lang = lang.toLowerCase();
import(`dayjs/locale/${lang}`).then(
() => {
dayjs.locale(lang);
setAdapterLocale(lang);
});
The thing is, when I run this code in browser and try to import 'dayjs/locale/fr-ca', for example, it works fine, but when 'fr-ca' comes from CefSharp, then the import fails with
Uncaught (in promise) TypeError: Failed to resolve module specifier
'dayjs/locale/fr-ca'
Any help is much appreciated.
If you want to use a dynamic path for the dynamic import then you'll first have to list all of the possible paths that you will potentially want to have, otherwise your bundler wont know which files to include.
You can add import('dayjs/locale/fr-ca') anywhere in your code and the bundler will include it when it builds your app for the browser.
And you'll still going to get that error if you don't have a locale for user's language, so you should catch that case:
import(`dayjs/locale/${lang}`).then(
() => {
dayjs.locale(lang);
setAdapterLocale(lang);
},
() => { // in case the import fails
// maybe default to english
dayjs.locale('en');
setAdapterLocale('en');
});
I figured it out. The problem was that when building the package for the .net app, the package was created using rollup (which is not the case when running in browser).
Rollup needs some special config to support dynamic import:
https://www.npmjs.com/package/#rollup/plugin-dynamic-import-vars

How can I pre-render a react app in gulp/node?

How can I programmatically render a react app in gulp and node 12?
I taking over and upgrading an old react (0.12.0) app to latest. This also involved upgrading to ES6. The react code itself is done, but we also need to prerender the application (The app is an interactive documentation and must be crawled by search engines).
Previously, the gulp build process ran browserify on the code and then ran it with vm.runInContext:
// source code for the bundle
const component = path.resolve(SRC_DIR + subDir, relComponent);
vm.runInNewContext(
fs.readFileSync(BUILD_DIR + 'bundle.js') + // ugly
'\nrequire("react").renderToString(' +
'require("react").createElement(require(component)))',
{
global: {
React: React,
Immutable: Immutable,
},
window: {},
component: component,
console: console,
}
);
I am suprised it worked before, but it really did. But now it fails, because the source uses ES6.
I looked for pre-made solutions, but they seem all targeting old react versions, where react-tools was still around.
I packaged the special server-side script below with browserify & babel and then ran it using runInNewContext. It does not fail but also not output any code, it just logs an empty object
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';
const content = renderToString(<App />);
I found tons of articles about "server-side rendering", but they all seem to be about rendering with express and use the same lines as the script above. I can't run that code directly in gulp, as it does not play well with ES6 imports, which are only available after node 14 (and are experimental).
I failed to show the gulp-browserify task, which was rendering the app component directly, instead of the server-side entrypoint script above. In case anyone ever needs to do this, here is a working solution.
Using vm.runInNewContext allows us to define a synthetic browser context, which require does not. This is important if you access window anywhere in the app.
src/server.js:
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';
const content = renderToString(<App />);
global.output = content;
above script serves as entry point to browserify. Gulp task to compile:
function gulpJS() {
const sourcePath = path.join(SRC_DIR, 'src/server.js');
return browserify(sourcePath, { debug:true })
.transform('babelify', {
presets: [
["#babel/preset-env", { targets: "> 0.25%, not dead" }],
"#babel/preset-react",
],
})
.bundle()
.pipe(source('server_output.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('.'))
.pipe(dest(BUILD_DIR));
}
The generated file can now be used by later tasks, e.g. to insert the rendered content into a HTML file.
const componentContent = fs.readFileSync(path.join(BUILD_DIR, 'server.js'));
const context = {
global: {
React: React,
Immutable: Immutable,
data: {
Immutable
},
},
window: {
addEventListener() { /* fake */ },
removeEventListener() { /* fake */ },
},
console,
};
vm.runInNewContext(componentContent, context);
const result = context.global.output;

How to fix 'Invariant Violation' caused by cyclic dependencies in react-redux

I have a React project set up like this:
It is a simple application. The Dashboard has a UserListContainer, containing a UserList, which lists four users with their ID and name. The UserList gets the Users from Data.ts
The application itself works just fine and displays the four users. But as soon as I try to test the UserList with enzymes shallow rendering, the tests give me the following error message:
Invariant Violation: You must pass a component to the function returned by connect. Instead received undefined
at invariant (node_modules/invariant/invariant.js:40:15)
at wrapWithConnect (node_modules/react-redux/lib/components/connectAdvanced.js:97:33)
at Object.<anonymous> (src/Users/UserListContainer.tsx:4:34)
at Object.<anonymous> (src/Users/index.ts:1:1)
at Object.<anonymous> (src/Dashboard/Dashboard.tsx:2:1)
at Object.<anonymous> (src/Dashboard/index.ts:1:1)
at Object.<anonymous> (src/Users/UserList.tsx:2:1)
at Object.<anonymous> (src/Users/__tests__/UserList.test.tsx:3:1)
The problem is basically that, even though we don't use the Dashboard when rendering the UserList shallowly, React still tries to build it. I guess that happens because we access Data through the Dashboard index, so React will also try to resolve Dashboard and its imports, namely UserListContainer, because they are exported through the same index file. When I import the users directly instead of through the index, the problem disappears.
We fixed this issue by breaking the cyclic dependency but if I encounter the error again, I want to know other ways to fix it. I would also like to understand why the web application still seems to be working just fine, while the tests fail.
Also, is there a way to prevent React from resolving the imports and exports when using enzymes shallow rendering?
Users/__tests__/UserList.test.tsx
test("reproduce the problem", () => {
const wrapper = shallow(<UserList />)
console.log(wrapper)
expect(1).toBe(1)
})
Users/UserList.tsx
import { Data } from "../Dashboard"
export const UserList: React.FC = () => (
<React.Fragment>
{Data.users.map(user => (
<div>
<code>{user.id} - </code>
<code>{user.name}</code>
</div>
))}
</React.Fragment>
)
Dashboard/index.ts
export { Dashboard } from "./Dashboard" // not used but still resolved
export { Data } from "./Data" // actually used
Dashboard/Data.ts
export const Data = {
users: [
{ id: "user1", name: "Albert" },
{ id: "user2", name: "Bertha" },
{ id: "user3", name: "Chloe" },
{ id: "user4", name: "Doug" }
]
}
Dashboard/Dashboard.tsx
import { UserListContainer } from "../Users"
export const Dashboard: React.FC = () => {
return <UserListContainer />
}
Users/UserListContainer.tsx
import { UserList } from "./UserList"
export const UserListContainer = connect()(UserList)
One way of fixing it would be to reorder the imports in your dashboard file:
export { Data } from "./Data" // actually used
export { Dashboard } from "./Dashboard" // not used but still resolved
Web application will work in most cases because it will start resolving from your index.tsx file (or whatever your entry file name is) and go from there. Jest on the other hand starts from your test file and only resolves those imports (you can find a nice explanation why this happens here: https://railsware.com/blog/how-to-analyze-circular-dependencies-in-es6/).
We had similar problems in our projects and unfortunatelly except reordering imports and better structuring your files there is no other solution.
One "hack" that you can also do is to add:
import 'problematic_module'
to your jest setupFilesAfterEnv. That way module will be resolved before each test (but i recommend this only as a last resort).

Tried to register two views with the same name ProgressBarAndroid

Using react version 16.0.0 with react-native version 0.49.1 raises the red screen error "Tried to register two views with the same name ProgressBarAndroid". Removing all imports and instances of ProgressBarAndroid results in a well functioning program. Downgrading to react-native version 0.48.4 works as well. How do I use ProgressBarAndroid with the latest React Native version?
React Native starting from version 0.49 triggers this error if you are trying to call requireNativeComponent() for same component more than once. Even if they are called from different modules.
I had similar issue with custom view MyCustomView. So I just wrapped it in a single module:
// MyCustomView.js
import {requireNativeComponent} from 'react-native'
const MyCustomView = requireNativeComponent('MyCustomView', null)
export default MyCustomView
Though it might not be your exact case the root cause is the same.
import ReactNative from 'react-native';
const description = Object.getOwnPropertyDescriptor( ReactNative, 'requireNativeComponent' )
if ( !description.writable ) {
Object.defineProperty( ReactNative, 'requireNativeComponent', {
value: (function () {
const cache = {}
const _requireNativeComponent = ReactNative.requireNativeComponent
return function requireNativeComponent( nativeComponent ) {
if ( !cache[ nativeComponent ] ) {
cache[ nativeComponent ] = _requireNativeComponent( nativeComponent )
}
return cache[ nativeComponent ]
}
})(), writable: true
} )
}
I experienced this during hot-reload in development. What causes the issue is the following: however JS is reloaded, the native code is still holding onto the same reference that it previously held onto. Whenever JS runs requireNativeComponent with the same viewName, it throws because the previous reference for the given viewName still exists. Here is the source file of requireNativeComponent, which clearly states that it should be memozied on the React Native side and only initialized once. Thus, the answer of #Teivaz is satisfying and no further hacking (like the answer of #蒋宏伟) is needed. If your code is structured well, you don't have to use any manual caching because your import structure solves it for you. :)

How to structure Meteor app and load into Meteor shell

I'm having a number of issues putting together a very simple piece of code as I learn Meteor. See the comments, which are questions.
server/main.js
import { Meteor } from 'meteor/meteor';
import { Post } from './schema'
// Why is this required to make Post available in Meteor.startup?
// Isn't there auto-loading?
Meteor.startup(() => {
console.log(Post)
// This works, but why isn't Post available to meteor shell?
});
server/schema.js
import { Post } from './models/post'
export { Post }
server/models/post.js
import { Class } from 'meteor/jagi:astronomy';
// Why can't this be imported elsewhere, like main.js?
const Posts = new Mongo.Collection('posts');
const Post = Class.create({
name: 'Post',
collection: Posts,
fields: {
title: { type: String },
userId: String,
publishedAt: Date
},
});
export { Post }
In addition to these questions, how can I load my app into meteor shell? Post is undefined there, even though it's defined in Meteor.startup. I tried using .load with an absolute path, but this breaks my app's imports, which use relative paths.
As for which errors I'm confused about:
When I try and use import inside Meteor.startup(), I get an error that the keyword import is undefined. I'm using the ecmascript package.
When I don't import { Class } in the same file where I use Class, I get an unknown keyword error.
If I don't import { Post } in main.js, then Post is undefined.
Not able to load app into Meteor shell.
To access exported objects in Meteor shell, use require:
> require('server/schema.js').Posts.findOne();
To access objects exported by packages, use the package name:
> require('react').PropTypes;
The reason you can't access an object that's imported by another js file is that each file has its own scope here. When Meteor builds your app, it doesn't just concatenate js files like many other build systems do, and that's really a good thing.
Basically a Javascript object gets created for every js file you write. Anything you export in a js file becomes a field in this object which you can access by using require. And import is just a nicer version of the same thing.

Categories