How to create a hello world application using isomorphic-webpack? - 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

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-hot-loader: `hot` could not find the `name` of the the `module` you have provided

I'm using Webpack 4 to create a React project with hooks and I'm trying to get the changes to reload on page live using react-hot-loader following this tutorial.
But I when I try npm start I get following error on the browser:
Error: React-hot-loader: hot could not find the name of the the
module you have provided
This is my App.js contents:
import React from 'react';
import { hot } from 'react-hot-loader';
import Header from './Header';
function App() {
return (
<section className="main">
<Header />
</section>
);
}
export default hot(App);
Alternately I tried importing hot from react-hot-loader/root, but this way I get a different error:
Error: React-Hot-Loader: react-hot-loader/root is not supported on
your system. Please use import {hot} from "react-hot-loader" instead
How could I solve this issue?
You should be requiring it before react:
import { hot } from 'react-hot-loader/root';
import React from 'react';
The package documentation mentions this.
Well, looking at my webpack configs:
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV) }),
],
devServer: {
contentBase: './dist',
hot: true,
},
I had used webpack.HotModuleReplacementPlugin() in plugins and hot: true in devServer which made the second error if I would use react-hot-loader/root.
So removing new webpack.HotModuleReplacementPlugin() from the webpack.config.js, solved my problem.
import { hot } from 'react-hot-loader';
export default hot(module)(App);
or
import { hot } from 'react-hot-loader/root';
export default hot(App);

Loading react component from url

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.

How does webpack v4 handle devDependencies in production mode?

I'm wondering how does webpack handle devDependencies when in production mode:
App.js
import { hot } from 'react-hot-loader';
function App() {
// App code
}
export default process.env.NODE_ENV === 'development' ? hot(module)(App) : App;
I can successfully use a ternary into the export statement. But I can't do that and neither set a condition in the import statement.
QUESTION
What is the proper way to handle this (the import of a devDependency)?
Will webpack add devDependencies to the bundle if no condition is placed at the import?
EDIT:
Just found out that webpack does add devDependencies to the bundle:
This was generated with webpack mode set to production:
Here's how I solved it with ignorePlugin
App.js
import { hot } from 'react-hot-loader';
function App() {
// App code
}
export default process.env.NODE_ENV === 'development' ? hot(module)(App) : App;
webpack.prod.js (webpack production config file)
module.exports = merge(common, {
mode: 'production',
plugins:[
new webpack.IgnorePlugin(/react-hot-loader/), // <------ WILL IGNORE THE react-hot-loader
new webpack.HashedModuleIdsPlugin(),
new BundleAnalyzerPlugin()
],
This way react-hot-loader is ignored in production mode.
In development I use another config file for webpack, which doesn't use the ignorePlugin.
You can have two new files for app, app.dev.js and app.prod.js while in app you just switch the require based on env.
// App.js
let App;
if (process.env.NODE_ENV === 'development') {
App = require('./app.dev.js')
} else {
App = require('./app.prod.js')
}
export default App
EDIT:
It's essential that require is used instead of import as only require can be used dynamically like this.

Module not found: Error: Can't resolve './components/PropTest1' - React JS

I have the following directory structure for my REACTJS app
/ReactJs
-dist
--app
-node_modules
-src
--app
--app/Hello.jsx
----components
----components/PropTest1.jsx
-src/main.html
package.json
webpack.config.js
My Hello.jsx code is:
import React, { Component } from 'react';
import ReactDOM, { render } from 'react-dom';
import PropTest1 from "./components/PropTest1"
var dest = document.querySelector('#container');
class Hello extends Component {
render() {
return (
<div>
<h1>Hello World</h1>
<PropTest1 />
</div>
);
}
}
render(<div><Hello /></div>, dest);
and PropTest1.jsx code is
import React, { Component } from 'react';
class PropTest1 extends Component {
render() {
return (
<div>
<p> My name is no one</p>
</div>
);
}
}
export default PropTest1;
and my webpack.config.js is
var webpack = require('webpack');
var path = require('path')
module.exports = {
mode: "development",
entry: path.resolve(__dirname, 'src') + "/app/Hello.jsx",
output: {
path: path.resolve(__dirname, 'dist') + "/app",
filename: 'bundle.js',
publicPath: '/app/'
},
module: {
rules: [{
test: /\.jsx?/,
include: path.resolve(__dirname,'src'),
loader:'babel-loader'
}]
},
resolve: {
extensions: ['*', '.js', '*.jsx']
}
};
When I am doing
npm run build
I am getting
Module not found: Error: Can't resolve './components/PropTest1'
What looks wrong with the above project, please check.
EDIT: I have added the resolve configuration in my webpack.config.js
The issue here is that you didn't specify the file extension (.jsx) while importing your component (import PropTest1 from "./components/PropTest1")
To solve this, you need to update Webpack config and add a resolve property, which will make Webpack look for files named (in your example) PropTest1.js, PropTest1.jsx until it finds the right one ...
module.exports = {
mode: "development",
entry: path.resolve(__dirname, 'src') + "/app/Hello.jsx",
...,
resolve: {
extensions: ['', '.js', '.jsx']
}
};
Currently,it is looking for components directory within app directory so, you need to use ..
import PropTest1 from "../components/PropTest1"
I found the issue with name of the file. While doing import I had
import Login from "./login";
While name of the file was Login.js
Running on the local machine was not giving error but when I was running on linux, it was giving me a similar error as above.

Resources