Loading react component from url - reactjs

I want to import the react component that I have bundled using web pack.
I am able to complete the task by copying it locally to that folder and then importing it like
import Any from '.dist/index'
and it is working fine.
But what I want to do is uploading this index.js file to somewhere for example Amazon s3. Now I am not able to import the component in the same way as mentioned above.
My webpack.config.js file, I have used to export my bundled component generated by webpack that I am using in another project by copying the index.js and index.css file is
var path = require("path");
var HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "index_bundle.js",
libraryTarget: "commonjs2"
},
module: {
rules: [
{ test: /\.(js)$/, use: "babel-loader" },
{ test: /\.css$/, use: ["style-loader", "css-loader"] }
]
},
externals: {
react: "commonjs react"
},
mode: "production",
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html"
})
]
};
I want to import the component from file url uploaded to s3.

you can do what you are describing with micro apps. A micro app is basically nothing more than a component that is lazy loaded into the host application from a url at runtime. There is no need to install or import the component at design time. There is a library available that lets you do this with a HOC component.
import React from 'react';
import ReactDOM from 'react-dom';
import MicroApp from '#schalltech/honeycomb-react-microapp';
const App = () => {
return (
<MicroApp
config={{
View: {
Name: 'redbox-demo',
Scope: 'beekeeper',
Version: 'latest'
}
}}
/>
);
});
export default App;
You can find more information on how it works here.
https://github.com/Schalltech/honeycomb-marketplace

This is not the way you should package and deploy your React components. AWS S3 is a bucket for storage of files to serve on the web. It's purpose is not to share code files through projects.
You should publish your React components to a registry such as NPM. After you publish your package to the registry, you should be able to install the package into your app as a dependency by doing something like npm install my_package.

Related

How to import SVG in ReactJS with craco?

I'm struggling to import SVG's when I'm using craco in my react app.
It's suggested to use #svgr/webpack but I'm not sure how to put it into my craco.config.js
My current setup as per this (I prob shouldn't follow someone's config that doesn't work and expect it to work tho) that does not work:
// craco.config.js
const CracoAlias = require("craco-alias");
module.exports = {
plugins: [
{
plugin: CracoAlias,
options: {
source: "tsconfig",
baseUrl: "./src",
tsConfigPath: "./tsconfig.paths.json"
}
},
],
webpack: {
configure: (config, { env, paths }) => {
config.module.rules.push({
test: /\.svg$/,
use: ["#svgr/webpack"]
});
return config;
}
}
};
The craco.config.js webpack documentation is here but it's so confusing to me without concrete examples.
Also to note:
Writing import {ReactComponent as mySvg} from "./mySvg.svg" doesn't work because it doesn't recognize it as a ReactComponent.
If I try importing directly via import mySvg from "./mySvg.svg" Typescript doesn't recognize the file.
What I'm currently doing is putting the svg into a React component and using that but it's a nightmare doing that every time. I also put this in #types/custom.d.ts, but it still doesn't work when put into <img src={mySvg} />
// #types/custom.d.ts
declare module "*.svg" {
const content: any;
export default content;
}
import {reactComponent as GoogleLogo} from "../assets/image/googlelogo.svg;
GoogleLogo is component and reactComponent is a required magic string
i find the fix your problem in Adding svgr to create-react-app via craco

React SSR alternatives

I am currently working on a project that someone else built and I was asked to implement server side rendering, it's a huge project and it uses a custom routing system based on a "builder JSON" taken by a main component that selects which components to render based on the route, it is meant to keep the app dynamic and to adjust to the needs of several customers.
I have been checking everywhere trying to find an answer but im new to SSR and it's a big challenge.
I am currently testing an approach using express that looks like this:
import 'babel-polyfill';
import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router';
import bodyParser from 'body-parser';
import { App } from '../src/App';
const app = express();
const PORT = process.env.PORT || 8000;
app.use(bodyParser.json());
app.use(express.static('ssrBuild'))
app.get('*', (req, res) => {
const context = {}
const content = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const html = `
<html>
<head>
</head>
<body>
<div id="root">
${content}
</div>
</body>
</html>
`;
res.send(html);
});
app.listen(PORT, () => {
console.log(`App running on port ${PORT}`);
});
The problem I am currently having is that the App component calls the "complex routing component" from another repository in the node_modules (also build by them), my webpack config is taking the App component and finding jsx, which cant obviouly be run in the server.
Webpack config:
const path = require('path');
const webpackNodeExternals = require('webpack-node-externals');
module.exports = {
target: 'node',
entry: {
server: './ssr/server.js',
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, '..', 'ssrBuild'),
publicPath: '/ssrBuild'
},
module: {
rules: [
{
test: /\js$/,
loader: 'babel-loader',
exclude: '/node_modules/',
options: {
presets: [
'#babel/react',
['#babel/preset-env', {
targets: { browsers: ['last 2 versions'] }
}]
],
plugins: [
['#babel/plugin-proposal-decorators', { 'legacy': true }],
'#babel/plugin-proposal-class-properties',
'#babel/plugin-syntax-function-bind',
'#babel/plugin-transform-async-to-generator',
'#babel/plugin-proposal-export-default-from',
'babel-plugin-jsx-control-statements',
'react-hot-loader/babel',
'lodash',
]
}
}
]
},
externals: [webpackNodeExternals()]
}
Is there a way I can tell webpack to transpile the jsx in the node_modules folder "on the go"? What other solutions could there be?
Also, the whole point of this project is to impprove the SEO for these apps, I would only need to SSR the index page and any direct link to content in it. No need to SSR the entire app is there a way this can be achieved?
I was also wondering if refactoring the entire app to use Next.js would be worth it if this were possible only for the index page and any direct link.
Thank you in advance!
If the team can afford it then you should definitely go and try a framework. This will me more maintainable on the long term. I would recommend you try Next.js over Gatsby, Both are great options but in my opinion Next has two or three advantages like Incremental Static Regeneration (Regenerate if your content change continuously) or you can choose between use Server Sider or Static generation based on your routes. You can use SSR on your dashboard and SSG on your home and landing pages for example.
If you don't need any type of pre-rendering you can go for client-side only and even then Next are gonna make a couple of optimization that will speed up your site.
On the long term it will save you a lot of time and it will be easy to maintain

React is undefined (Cannot read property 'createElement' of undefined)

I'm trying to convert a working ReactJS application into TypeScript, and I've had some issues getting anything to work properly.
import React from "react";
import * as ReactDOM from "react-dom";
import Application from "./Application";
console.log(React); // undefined
ReactDOM.render(
<Application/>, window.document.getElementById("application-wrapper")
);
The console throws an error at <Application />
When I import react like this, react loads:
import * as React from "react";
However, I want to use the import statement using the default export, because I import React using this import syntax in all the existing components:
import React, {Component} from "react";
export default class Whatever extends Component<Props, State> {
...
}
My tsconfig.json file contains this line allowing synthetic defaults:
"allowSyntheticDefaultImports": true
My webpack.config.js file:
let path = require("path");
let config = {
entry: "./src/main.tsx",
output: {
path: path.resolve(__dirname, "build"),
filename: "bundle.js"
},
devtool: "source-map",
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"]
},
module: {
loaders: [
{
test: /\.tsx?$/,
loader: "ts-loader",
exclude: /node_modules/
}
]
}
};
module.exports = config;
Not sure what I'm missing here....
Set "esModuleInterop": true instead.
In your typescript configuration i.e tsconfig.json "esModuleInterop": true and "allowSyntheticDefaultImports": true. this will allow you to import CommonJS modules in compliance with es6 modules spec.
Module resolution is a little complicated because Typescript does it different than Babel and Webpack. If you want to know more you can check this comment: https://github.com/Microsoft/TypeScript/issues/5565#issuecomment-155216760
Going back to your problem, allowSyntheticDefaultImports tells Typescript to allow default imports from modules with no default export but the emitted code doesn't change. Because of that, you need to move the responsibility of resolving modules to Webpack or Babel.
To achieve that set moduleResolution module to ES6es2015 in the Typescript config file.
The pipeline will look like this:
TS Code => (TypescriptCompiler) => JS Code with ES6 modules => (Webpack modules resolver) => JS Code

How to create a hello world application using isomorphic-webpack?

I want to create a simple application that outputs "Hello, World!" using isomorphic-webpack.
The most simple way is to use the createIsomorphicWebpack high-level abstraction.
First, you need to have have a basic webpack configuration.
webpack configuration does not need to define any special configuration for isomorphic-webpack, e.g. this will work:
import path from 'path';
import webpack from 'webpack';
const webpackConfiguration = {
context: __dirname,
entry: {
'app': [
path.resolve(__dirname, './app')
]
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].js'
},
module: {
loaders: []
}
};
Next, run createIsomorphicWebpack:
import {
createIsomorphicWebpack
} from 'isomorphic-webpack';
createIsomorphicWebpack(webpackConfiguration);
What this does is:
Creates a new webpack compiler.
Runs compiler in watch mode.
Overrides require to use compiled assets.
Therefore, now all you need is to require the entry script:
import {
createServer
} from 'http';
http
.createServer((request, response) => {
response.writeHead(200, {
'Content-Type': 'text/html'
});
response.end(request('./app'));
})
listen(8000);
The entry script must be environment aware, i.e. it must return for node.js process and it must use whatever client specific logic otherwise, e.g.
import React from 'react';
import ReactDOM from 'react-dom';
import style from './style.css';
const app = <div className={style.greetings}>Hello, World!</div>;
if (typeof process === 'undefined' || !process.release || process.release.name !== 'node') {
ReactDOM.render(app, document.getElementById('app'));
}
export default app;
Since this entry script is using css and react, you will need to add the missing loaders to your webpack configuration:
babel-loader and babel-react-preset
css-loader
style-loader

Webpack not bundling node modules imported in dependency JS files

I'm using Webpack to bundle my ReactJS application.
helloworld.js
import React from 'react';
export default class HelloWorld extends React.Component {
render() {
return <h2>Hello {this.props.name}!</h2>;
}
}
index.js
import ReactDOM from 'react-dom';
import HelloWorld from './helloworld';
ReactDOM.render(<HelloWorld name="World" />,
document.getElementById('container'));
webpack.config.js
module.exports = {
entry: './index.js',
output: 'bundle.js',
module: {
loaders: [
{
test: /(\.js|\.jsx)/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
}
};
When I run webpack-dev-server --progress --colors I'm getting an error in the browser "React is not defined" but if I import React directly in the index.js then the error not comes. Why Webpack is not including React in the bundle if it is referenced in the helloworld.js file?
Well webpack only tries to bundle up the individual modules by reading the dependencies in it and resolving them to render a particular element. Now while bundling
ReactDOM.render(<HelloWorld name="World" />,
document.getElementById('container'));
ReactDOM tries to execute React.createElement(_Helloworld2.default, { name: 'World' }), document.getElementById('app') function which requires React as a dependency that is not present in your index.js file so it gives an error and solve the issue when you import React in your index.js file. I hope I was able to explain and my answer helps you.
You are missing import React from 'react'; statement.
You will need it every time You write some JSX in a file, because it is transformed into React.createElement(..) function calls.

Resources