There was a problem with importing react component with JXS. Components are imported from library (used like a SDK).
/sdk/dist/js/app.js
import React, { Component } from 'react';
export default class Test extends Component {
render() {
return <div>Hello</div>;
}
}
There is a project where this SDK is used, there is webpack / babel that already does a build, the file with import of this component looks like this:
app/js/index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Test from 'sdk/dist/js/App';
Result:
BUT!
Everything will work if:
We remove JSX from this component
app/js/index.js
import React, { Component } from 'react';
export default class Test extends Component {
render() {
return React.createElement(
"div",
null,
"Hello"
);
}
}
Remove import and insert component directly.
app/js/index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Test extends Component {
render() {
return <div>Hello</div>;
}
}
The problem is that it needs to work through import. I suggest that the problem is that the webpack does not transpose the imported file - and reads it as is ...
webpack:
{
entry: './app/js/index.js',
output: {
path: resolve(__dirname, plConfig.paths.public.root),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true
}
}
]
}
]
}
.babelrc:
{
"presets": [
"#babel/preset-env",
"#babel/preset-react"
]
}
You'll need a babel plugin to transform jsx...
#babel/plugin-transform-react-jsx
Install
npm i -D #babel/plugin-transform-react-jsx
Use in .babelrc
{
presets: [ ... ],
plugins: [ "#babel/plugin-transform-react-jsx", ...other plugins ]
}
EDIT:
You also need to add a babel rule for jsx...
In your webpack module rules...
Change test: /\.js$/ to test: /\.jsx?$/
Related
So basically I want to render one single React component (a notification component) into my Angular project. I created Notification.tsx
import * as React from 'react';
import { FunctionComponent, useEffect, useRef, useState } from 'react';
import { IconButton, Badge, Menu, List, ListItem, ListItemIcon, ListItemText, ListItemSecondaryAction, Avatar } from '#material-ui/core';
import { Notifications, Delete, Event, HourglassEmpty, Alarm } from '#material-ui/icons';
import { makeStyles } from '#material-ui/core/styles';
import { grey } from '#material-ui/core/colors';
export interface NotificationProps { }
export const NotificationComponent: FunctionComponent<NotificationProps> = (props: NotificationProps) => {
return <div className={"row"}>
<IconButton disableRipple={true} aria-label="notification" className="py-3 my-auto"
onClick={handleNotificationMenuClick} aria-controls="notification-drop-down-menu"
aria-haspopup="true">
<Badge badgeContent={4} max={99} color="secondary">
<Notifications />
</Badge>
</IconButton>
</div>
};
A wrapper component NotificationWrapper.tsx
import { AfterViewInit, Component, ElementRef, OnChanges, OnDestroy, SimpleChanges, ViewChild, ViewEncapsulation } from '#angular/core';
import { NotificationComponent } from './Notification';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
const containerElementName = 'notificationComponentTemplate';
#Component({
selector: 'react-notification-component',
template: `<span #${containerElementName}></span>`,
encapsulation: ViewEncapsulation.None,
})
export class NotificationWrapper implements OnChanges, OnDestroy, AfterViewInit {
#ViewChild(containerElementName, { static: false }) containerRef: ElementRef;
constructor() { }
ngOnChanges(changes: SimpleChanges): void {
this.render();
}
ngAfterViewInit() {
this.render();
}
ngOnDestroy() {
ReactDOM.unmountComponentAtNode(this.containerRef.nativeElement);
}
private render() {
ReactDOM.render(<div className={'notification-wrapper'}>
<NotificationComponent />
</div>, this.containerRef.nativeElement);
}
}
Added this wrapper to app.module.ts's #NgModule
import { NotificationWrapper } from "../react-components/notification/NotificationWrapper";
#NgModule({
declarations: [
NotificationWrapper,
],
})
Used the notification wrapper selector as follows:
<div class="col-sm-6">
<react-notification-component></react-notification-component>
</div>
Everything works fine when served locally and as I went through other similar questions on this site: I've added "jsx": "react" to tsconfig.json,
plugins: [
new webpack.ProvidePlugin({
"React": "react",
})
]
and
externals: {
'react': 'React'
},
to webpack.config.js. Here's the whole file for reference.
// Work around for https://github.com/angular/angular-cli/issues/7200
const path = require('path');
const webpack = require('webpack');
// change the regex to include the packages you want to exclude
const regex = /firebase\/(app|firestore)/;
module.exports = {
mode: 'production',
entry: {
// This is our Express server for Dynamic universal
server: './server.ts'
},
externals: {
'./dist/server/main': 'require("./server/main")',
'react': 'React'
},
target: 'node',
node: {
__dirname: false,
__filename: false,
},
resolve: { extensions: ['.ts', '.js'] },
target: 'node',
mode: 'none',
// this makes sure we include node_modules and other 3rd party libraries
externals: [/node_modules/, function (context, request, callback) {
// exclude firebase products from being bundled, so they will be loaded using require() at runtime.
if (regex.test(request)) {
return callback(null, 'commonjs ' + request);
}
callback();
}],
optimization: {
minimize: false
},
output: {
// Puts the output at the root of the dist folder
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
noParse: /polyfills-.*\.js/,
rules: [
{ test: /\.ts$/, loader: 'ts-loader' },
{
// Mark files inside `#angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
test: /(\\|\/)#angular(\\|\/)core(\\|\/).+\.js$/,
parser: { system: true },
},
]
},
plugins: [
new webpack.ProvidePlugin({
"React": "react",
}),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
]
};
My problem is, when I build my app, the notification component is not rendered and I get this error in console ERROR ReferenceError: React is not defined. Is there anything that I missed? Thanks in advance.
Add the following to tsconfig.json
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"jsx": "react",
}
Set aot and buildOptimizer to false in angular.json
Replace
import * as React from 'react';
import * as ReactDOM from 'react-dom'
with
import React from 'react';
import ReactDOM from 'react-dom';
I think it's a typical unwanted optimization that remove React in the final js (React isn't directly used)
Try to call a method or an attribute on React like React.version :
import {
OnChanges,
ViewChild
} from '#angular/core';
import { MyComponent } from './react/MyComponent';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
const containerElementName = 'myReactComponentContainer';
#Component({
...
})
export class MyComponent implements OnChanges {
#ViewChild(containerElementName) containerRef: ElementRef;
ngOnChanges(changes: SimpleChanges): void {
this.render();
}
private render() {
React.version;
ReactDOM.render(<MyReactComponent />, this.containerRef.nativeElement);
}
}
I'm trying to compile this index.js file using rollup:
import React from "react";
import ReactDOM from "react-dom";
import Grid from "#material-ui/core/Grid";
ReactDOM.render(
<React.StrictMode>
<Grid container>
</Grid>
</React.StrictMode>,
document.getElementById('root')
);
rollup.config.js:
import { nodeResolve } from '#rollup/plugin-node-resolve';
import babel from '#rollup/plugin-babel';
import commonjs from '#rollup/plugin-commonjs';
export default {
input: 'index.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
nodeResolve(),
babel({ babelHelpers: 'bundled', exclude: /node_modules/ }),
commonjs(),
],
};
babel.config.json:
{
"presets": [
"#babel/preset-react",
"#babel/preset-env"
]
}
Now, when I run npx rollup -c i get this error:
[!] Error: Could not load /home/recursive-beast/Desktop/repositories/myproject/node_modules/#babel/runtime/helpers/esm/objectWithoutProperties (imported by node_modules/#material-ui/core/esm/Grid/Grid.js): ENOENT: no such file or directory, open '/home/recursive-beast/Desktop/repositories/myproject/node_modules/#babel/runtime/helpers/esm/objectWithoutProperties'
This is unexpected because #babel/runtime is a dependency of #material-ui/core, and I already checked that it is installed in the node_modules folder.
I've been trying to figure out the solution since yesterday without success, so what could be the source of the problem?
I found a workable solution.
I just add the #rollup/plugin-alias plugin
... //other code
const alias = require('#rollup/plugin-alias');
module.exports = [
{
... // other config
plugins: [
alias({
entries: [
{ find: '#ui/lab', replacement: '#material-ui/lab/esm' },
{ find: '#ui/core', replacement: '#material-ui/core/esm' },
{ find: '#ui/icons', replacement: '#material-ui/icons/esm' },
{ find: /^#babel\/runtime\/helpers\/(.*)$/, replacement: '#babel/runtime/helpers/$1.js' }
]
}),
...// other plugins
],
},
]
Use #material-ui in js files
import Alert from '#ui/lab/Alert'
import AppBar from '#ui/core/AppBar'
import Toolbar from '#ui/core/Toolbar'
import Grid from '#ui/core/Grid'
import Paper from '#ui/core/Paper'
import Container from '#ui/core/Container'
import PlayIcon from '#ui/icons/PlayArrow'
import {
createMuiTheme,
ThemeProvider,
makeStyles,
createStyles
} from '#ui/core/styles'
import red from '#ui/core/colors/red'
... // other code
Above, hope it helps.
We had the same, after days of researching we solved it by setting jail: '/A_PATH_THAT_DOESNT_EXIST' to nodeResolve to be like the following.
nodeResolve({
// Lock the module search in this path (like a chroot). Module defined
// outside this path will be marked as external
jail: '/A_PATH_THAT_DOESNT_EXIST', // Default: '/'
})
I'm trying to learn React with node.js following an online tutorial https://www.tutorialspoint.com/reactjs/reactjs_environment_setup.htm. When I run the Main.js I got the following error:(function (exports, require, module, __filename, __dirname) { import React from 'react';
SyntaxError: Unexpected token import
at Object.exports.runInThisContext (vm.js:76:16)
....
Here's the main.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
ReactDOM.render(<App />, document.getElementById('app'));
And the app.jsx:
import React from 'react';
class App extends React.Component {
render() {
return (
<div>
Hello World!!!
</div>
);
}
}
export default App;
Webpack.config.js:
var config = {
entry: './main.js',
output: {
path:'./',
filename: 'index.js',
},
devServer: {
inline: true,
port: 8080
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
]
}
}
module.exports = config;
I searched for answers. Some said to use 'require' rather than import. I didn't quite understand how to use it or whether it's related to this issue. Can someone please help to explain? Many thanks in advance!
I just simply want to export and import a child component into my rot-directory (App.js) and render it out in the browser, but I get this error message in terminal "Module not found: Error: Cannot resolve 'file' or 'directory'". I don't understand what I typed wrong or why I cannot import my child to my App.js.
Have tried to solve this problem but with no results. I've been testing this in my "App.js" to get a more explicit name but not working:
import { ContactsList } from './ContactsList';
I've also tried typing this in my "ContactsList.js" but with no result:
export default class ContactsList extends React.Component {}
I'am a beginner so excuse me for my knowledge but I really want to learn this and the power of react. Please help me for better understanding!
--------App.js---------
import React from 'react';
import ReactDOM from 'react-dom';
import ContactsList from './ContactsList';
class App extends React.Component {
render() {
return (
<div>
<h1>Contacts List</h1>
<ContactsList />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'));
--------ContactsList.js---------
import React from 'react';
import ReactDOM from 'react-dom';
class ContactsList extends React.Component {
render() {
return (
<ul>
<li>Joe 555 555 5555</li>
<li>Marv 555 555 5555</li>
</ul>
)
}
}
export default ContactsList;
--------webpack.config.js---------
module.exports = {
entry: './src/App.js',
output: {
path: __dirname,
filename: 'app.js'
},
module: {
loaders: [{
test:/\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}]
}
};
In your ContactsList.js file, use a <div> to wrap the <ul>
Also in your webpack config file. Can you try to use loader : "babel-loader" instead of loader: 'babel'(Don't forget to install the babel-loader package)
Also remove the query part and try to create a separate .babelrc file with the following settings:
{
"presets" : [
"react",
"es2015"
]
}
Hope this can solve your problem
According to es6 module mechanism the default module should be
imported without {}
import ContactsList from './ContactsList';
and export like
export default class ContactsList extends React.Component {}
But I guess you are trying babel on .jsx extension however it seams
you are using ContactsList.js
Just change the to .jsx to .js in
--webpack.config.js
module.exports = {
entry: './src/App.js',
output: {
path: __dirname,
filename: 'app.js'
},
module: {
loaders: [{
test:/\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}]
}
};
Hope it works
You need to do some changes on webpack.config.js file. first replace
test:/\.jsx?$/,
with
test: /\.(js|jsx)$/,
Secondly import modules as follows
import ContactsList from 'path-of-the-file';
But you need to provide the actual path. to get the path correct there are many plugins available depending on the text editors we use. i am using https://github.com/sagold/FuzzyFilePath
I am using webpack and babel. I have a file like this:
import React from 'react';
import ReactRedux from 'react-redux';
var Layout = React.createClass({
render(){
return (<div>Markup</div>);
}
});
function mapStateToProps(state, action) {
return state;
}
export default ReactRedux.connect(mapStateToProps)(Layout);
For some reason when I run webpack, after compiling, it runs with this error: Cannot read property 'connect' of undefined. Not sure why it would fail at getting ReactRedux object. My webpack config is like this:
var compiler = webpack({
entry: "./dist/runner.js",
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel', // 'babel-loader' is also a legal name to reference
query: {
presets: ['es2015', 'react']
}
}
]
},
devtool: 'source-map',
output: {
filename: "public/dist/bundle.js"
}
});
This is because the react-redux package doesn't have a default export on the module. You can access the connect function manually like:
import { connect } from 'react-redux';
...
export default connect(mapStateToProps)(Layout);