React express SSR can't read CSS on the server - reactjs

I've been trying to learn React SSR with babel/webpack. I've gotten to the point of rendering the HTML on the page but once I start adding CSS I start getting errors saying
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> body {
| color: red
| }
index.js
import React from 'react';
import { hydrateRoot } from 'react-dom/client';
import App from './App';
const container = document.getElementById('root');
hydrateRoot(container, <App/>);
App.js
import { useState } from 'react';
import React from 'react';
import './App.css'
function App() {
const [counter, setCounter] = useState(0);
const incrementHandler = () => {
setCounter(prev => {
return ++prev
})
}
const decrementHandler = () => {
setCounter(prev => {
return --prev
})
}
return (
<div>
<button onClick={incrementHandler}>Increment</button>
<br/>
<button onClick={decrementHandler}>Decrement</button>
<br/>
{counter}
</div>
);
}
export default App;
server.js
import express from "express";
import React from "react";
import ReactDOMServer from "react-dom/server";
import App from "./src/App.js";
import path from "path";
const app = express();
app.use(express.static(path.resolve(__dirname, "build")));
app.get("*", (req, res) => {
let html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React-SSR</title>
</head>
<body>
<div id="root">${ReactDOMServer.renderToString(<App />)}</div>
<script src="bundle.js"></script>
</body>
</html>`;
res.send(html);
});
app.listen(3000, () => {
console.log("server listening on port 3000");
});
webpack-config-server.js
const path = require("path");
const nodeExternals = require('webpack-node-externals');
module.exports = {
mode: 'development',
target: 'node',
entry: './server',
externals: [nodeExternals()],
output: {
path: path.resolve(__dirname),
filename: "server-start.js",
},
devServer: {
port: 3010,
static: true,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['#babel/preset-env', "#babel/preset-react"]
}
},
},
],
}
};
webpack.config.js
const path = require("path");
module.exports = {
mode: 'development',
target: 'web',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: "bundle.js",
publicPath: '/'
},
devServer: {
port: 3010,
static: true,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['#babel/preset-env', "#babel/preset-react"]
}
},
},
{
test: /\.css$/,
use: [
'style-loader', 'css-loader'
]
}
],
}
};
These are the scripts in my package.json
"scripts": {
"build-react": "webpack",
"build-server": "webpack --config webpack.config-server.js",
"start": "node server-start",
"dev": "npm-run-all build-react build-server start --parallel"
},
Also how can I make it so when I change something in the App.js the app rebuilds and I see the change(I tried with webpack server but the "dev" script stops on build-react)

Related

isomorphic-style-loader doesn't work as it supposed to

Hey I am doing this simple react + SSR project that incorporates the isomorphic-style loader. I followed the step-by-step guide to implement it as detailed here https://www.npmjs.com/package/isomorphic-style-loader but it just doesn't work. The style I made is not showing. Can anyone guide me in fixing this issue?
Here is my webpack config
var path = require('path');
var webpack = require('webpack');
var nodeExternals = require('webpack-node-externals');
var browserConfig = {
entry: './src/browser/index.js',
output: {
path: path.resolve(__dirname, 'public'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{
test: /\.css$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
'postcss-loader',
],
},
],
},
mode: 'production',
plugins: [
new webpack.DefinePlugin({
__isBrowser__: 'true',
}),
],
};
var serverConfig = {
entry: './src/server/index.js',
target: 'node',
externals: [nodeExternals()],
output: {
path: __dirname,
filename: 'server.js',
publicPath: '/',
},
mode: 'production',
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{
test: /\.css$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
'postcss-loader',
],
},
],
},
plugins: [
new webpack.DefinePlugin({
__isBrowser__: 'false',
}),
],
};
module.exports = [browserConfig, serverConfig];
here is my index.js (server)
import express from 'express';
import cors from 'cors';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter, matchPath } from 'react-router-dom';
import serialize from 'serialize-javascript';
import StyleContext from 'isomorphic-style-loader/StyleContext';
import App from '../shared/App';
import routes from '../shared/routes';
const app = express();
app.use(cors());
app.use(express.static('public'));
app.get('*', (req, res, next) => {
const css = new Set(); // CSS for all rendered React components
const insertCss = (...styles) =>
styles.forEach((style) => css.add(style._getCss()));
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {};
const promise = activeRoute.fetchInitialData
? activeRoute.fetchInitialData(req.path)
: Promise.resolve();
promise
.then((data) => {
const context = { data };
const markup = renderToString(
<StyleContext.Provider value={{ insertCss }}>
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
</StyleContext.Provider>
);
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>SSR with RR</title>
<script src="/bundle.js" defer></script>
<script>window.__INITIAL_DATA__ = ${serialize(data)}</script>
<style type="text/css">${[...css].join('')}</style>
</head>
<body>
<div id="app">${markup}</div>
</body>
</html>
`);
})
.catch(next);
});
app.listen(3000, () => {
console.log(`Server is listening on port: 3000`);
});
here is my index.js (browser)
import React from 'react';
import { hydrate } from 'react-dom';
import App from '../shared/App';
import { BrowserRouter } from 'react-router-dom';
import StyleContext from 'isomorphic-style-loader/StyleContext';
const insertCss = (...styles) => {
const removeCss = styles.map((style) => style._insertCss());
return () => removeCss.forEach((dispose) => dispose());
};
hydrate(
<StyleContext.Provider value={{ insertCss }}>
<BrowserRouter>
<App />
</BrowserRouter>
</StyleContext.Provider>,
document.getElementById('app')
);
and here is a component inside the App.js which uses the css styling that does not work.
import React from 'react';
import { NavLink } from 'react-router-dom';
import style from './css/style.css';
import withStyles from 'isomorphic-style-loader/withStyles';
function Navbar() {
const languages = [
{
name: 'All',
param: 'all',
},
{
name: 'JavaScript',
param: 'javascript',
},
{
name: 'Ruby',
param: 'ruby',
},
{
name: 'Python',
param: 'python',
},
{
name: 'Java',
param: 'java',
},
];
return (
<ul className='navbar'>
{languages.map(({ name, param }) => (
<li key={param}>
<NavLink
activeStyle={{ fontWeight: 'bold' }}
to={`/popular/${param}`}
>
{name}
</NavLink>
</li>
))}
</ul>
);
}
export default withStyles(style)(Navbar);
I faced the same problem. Problem is related with css-loader. By default, css-loader generates JS modules that use the ES modules syntax. isomorphic-style-loader needs a CommonJS modules syntax.
Try this:
{
loader: 'css-loader',
options: {
importLoaders: 1,
esModule: false,
},
}

React-Hot-Loader Not Preserving State. v.4.12.21

I followed steps from given https://www.npmjs.com/package/react-hot-loader
Install
npm install react-hot-loader
Add react-hot-loader/babel to your .babelrc:
//.babelrc
{
"plugins": ["react-hot-loader/babel"]
}
Mark your root component as hot-exported:
//Button.js
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 1,
};
}
handleClick = () =>
this.setState({
counter: this.state.counter + 1,
});
render() {
return (
<div>
<h2> Cool Counter {this.state.counter} !!!!</h2>
<button onClick={this.handleClick}>{this.state.counter}</button>
</div>
);
}
}
export default hot(Button);
//App.js
import React from 'react';
import { hot } from 'react-hot-loader/root';
import Button from './controls/Button';
const App = () => (
<div style={{ color: 'purple' }}>
<Button />
</div>
);
export default hot(App);
Make sure react-hot-loader is required before react and react-dom:
//Main.js
import 'react-hot-loader';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import './main.scss';
ReactDOM.render(<App />, document.getElementById('container'));
If you need hooks support, use #hot-loader/react-dom
npm install #hot-loader/react-dom
Use webpack aliases
// webpack.config.js
module.exports = {
// ...
resolve: {
alias: {
'react-dom': '#hot-loader/react-dom',
},
},
};
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React-Hot-Loader-Test</title>
</head>
<body>
<div id="container"></div>
<script src="/public/main.js"></script>
<link href="/public/main.css" rel="stylesheet" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
</body>
//server.js
var webpack = require('webpack');
var WebPackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebPackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
}).listen(8080, 'localhost', function (err, result) {
if (err) {
return console.log(err);
}
console.log('Listening on localhost:8080');
});
//webpack.config.js
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
mode: 'development',
devtool: 'inline-source-map',
entry: {
main: ['react-hot-loader/patch', './src/main.js'],
},
resolve: {
alias: {
'react-dom': '#hot-loader/react-dom',
},
modules: [path.resolve('./src'), path.resolve('./node_modules')],
},
output: {
path: path.resolve(__dirname, 'public'),
filename: devMode ? '[name].js' : '[name].[chunkhash].js',
publicPath: '/public/',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['react-hot-loader/webpack', 'babel-loader'],
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
'css-loader',
'sass-loader',
],
},
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: devMode ? '[name].css' : 's[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
}),
],
};
//.babelrc
{
"presets": ["#babel/preset-env", "#babel/preset-react"],
"plugins": ["#babel/plugin-proposal-class-properties", "react-hot-loader/babel"]
}
Finally running 2 command
1. webpack -d
2. node server.js
result:
λ node server up and running
i 「wds」: Project is running at http://localhost:8080/
i 「wds」: webpack output is served from /public/
i 「wds」: Content not from webpack is served from G:\Projects\React-Second
i 「wds」: 404s will fallback to /index.html
react hot loading only working for html,css,jsx change
Question:
Hooks not storing previous state upon cliking button and then changing any css,html or jsx, UseState or Set state not preserving the state, it always starts with 1.
Please help what did i miss, i'am struggling from hours.
Regards
Shaz
Found the solution
//webpack.config.js
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
mode: 'development',
devtool: 'inline-source-map',
entry: {
main: ['webpack-dev-server/client?http://localhost:8080', 'webpack/hot/only-dev-server', './src/main.js'],
// main: ['react-hot-loader/patch', './src/main.js'],
},
resolve: {
alias: {
'react-dom': '#hot-loader/react-dom',
},
modules: [path.resolve('./src'), path.resolve('./node_modules')],
},
output: {
path: path.resolve(__dirname, 'public'),
filename: devMode ? '[name].js' : '[name].[chunkhash].js',
publicPath: '/public/',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
// use: {
// loader: 'babel-loader',
// // options: {
// // presets: ['#babel/preset-env', '#babel/preset-react'],
// // },
// },
use: ['react-hot-loader/webpack', 'babel-loader'],
//use: ['babel-loader'],
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
'css-loader',
'sass-loader',
],
},
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: devMode ? '[name].css' : 's[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
}),
],
// devServer: {
// contentBase: path.join(__dirname),
// compress: false,
// port: 8080,
// historyApiFallback: true,
// watchContentBase: false,
// publicPath: '/public/',
// },
};

Uncaught Error: Target container is not a DOM element. in React

I encountered this error when trying to set up my React app. I have looked at other people's solution, but didn't seem to find the solution that works for me.
I normally just do create-react-app, but this time I try to configure webpack and I'm not sure what went wrong here.
my index.js and App.js files are both in the src folder and my index.html is inside the dist folder
THANK YOU FOR YOUR HELP
my index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>High Five</title>
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
my webpack.config.js
const webpack = require("webpack");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const config = {
entry: ["react-hot-loader/patch", "./src/index.js"],
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
{
test: /\.png$/,
use: [
{
loader: "url-loader",
options: {
mimetype: "image/png",
},
},
],
},
{
test: /\.svg$/,
use: "file-loader",
},
],
},
resolve: {
extensions: [".js", ".jsx"],
alias: {
"react-dom": "#hot-loader/react-dom",
},
},
devServer: {
contentBase: "./dist",
},
plugins: [
new HtmlWebpackPlugin({
appMountId: "app",
filename: "index.html",
}),
new MiniCssExtractPlugin(),
],
};
module.exports = config;
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./styles.css";
ReactDOM.render(<App />, document.getElementById("app"));
App.js
import React, { Component } from "react";
import { hot } from "react-hot-loader/root";
class App extends Component {
render() {
return (
<div>
<h1>Hello React</h1>
</div>
);
}
}
export default hot(App);

Webpack config for SSR SCSS

I have a React-TypeScript SSR app where I used SCSS files for my styling. I need to write a rule in Webpack to load the SCSS and I haven't been able to do it.
I found various solutions online, all of which are extremely complex and use things like mini-css-extract-plugin. I couldn't get any of them to work.
I currently have two webpack config files, one for the client (web) and one for the server (node), both of which load the SCSS as such:
{
test: /\.scss$/,
use: ["css-loader", "sass-loader"]
}
I also encountered another issue in that I can't use style-loader as it throws an error about the window object. Does anyone have a working example (simple preferably) of loading SCSS in Webpack?
You are on right track with 2 web config file you can use
https://gist.github.com/mburakerman/629783c16acf5e5f03de60528d3139af
But don't set any other config file like babel.rc .yaml etc or other definition in project.json
try this
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
//..
plugins: [
new MiniCssExtractPlugin({
filename: 'assets/css/bundle-[contenthash].css',
chunkFilename: 'assets/css/bundle-[contenthash].css'
})
],
Look full example https://github.com/dewelloper/pzone/blob/master/webpack.config.store.js
A boilerplate for server-side rendering using react, webpack, Sass
(for both css-modules and pure sass)
webpack.config.js
const path = require('path');
const isDevelopment = true;
module.exports = [
{
name: 'client',
target: 'web',
entry: './client.jsx',
output: {
path: path.join(__dirname, 'static'),
filename: 'client.js',
publicPath: '/static/',
},
resolve: {
extensions: ['.js', '.jsx']
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules\/)/,
use: [
{
loader: 'babel-loader',
}
]
},
{
test: /\.scss$/,
use: [
{
loader: 'style-loader',
},
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[name]__[local]___[hash:base64:5]",
},
sourceMap: isDevelopment,
}
},
{
loader: 'sass-loader'
}
]
}
],
},
},
{
name: 'server',
target: 'node',
entry: './server.jsx',
output: {
path: path.join(__dirname, 'static'),
filename: 'server.js',
libraryTarget: 'commonjs2',
publicPath: '/static/',
},
devtool: 'source-map',
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules\/)/,
use: [
{
loader: 'babel-loader',
}
]
},
{
test: /\.scss$/,
use: [
{
loader: 'isomorphic-style-loader',
},
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[name]__[local]___[hash:base64:5]",
},
sourceMap: isDevelopment,
}
},
{
loader: 'sass-loader'
}
]
}
],
},
}
];
dev dependencies:
npm i -D #babel/cli #babel/preset-es2015 #babel/core #babel/plugin-proposal-class-properties #babel/preset-env #babel/preset-react babel-core babel-loader babel-plugin-lodash babel-plugin-react-transform babel-preset-env babel-preset-es2015 babel-preset-react babel-preset-stage-0 css-loader express isomorphic-style-loader node-sass sass-loader style-loader webpack webpack-dev-middleware webpack-hot-middleware webpack-hot-server-middleware
and dependencies:
npm i react react-dom react-helmet react-router-dom
sever.jsx:
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import {Helmet} from "react-helmet";
import Template from './template';
import App from './App';
export default function serverRenderer({ clientStats, serverStats }) {
return (req, res, next) => {
const context = {};
const markup = ReactDOMServer.renderToString(
<StaticRouter location={ req.url } context={ context }>
<App />
</StaticRouter>
);
const helmet = Helmet.renderStatic();
res.status(200).send(Template({
markup: markup,
helmet: helmet,
}));
};
}
App.jsx:
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Menu from './Menu'
import Helmet from "react-helmet";
import homepageStyles from './homepage.scss';
class Homepage extends Component {
render() {
return (
<div className={ homepageStyles.component }>
<Helmet
title="Welcome to our Homepage"
/>
<Menu />
<h1>Homepage</h1>
</div>
);
}
}
class About extends Component {
render() {
return (
<div>
<h1>About</h1>
</div>
);
}
}
class Contact extends Component {
render() {
return (
<div>
<h1>Contact</h1>
</div>
);
}
}
export default class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Helmet
htmlAttributes={{lang: "en", amp: undefined}} // amp takes no value
titleTemplate="%s | React App"
titleAttributes={{itemprop: "name", lang: "en"}}
meta={[
{name: "description", content: "Server side rendering example"},
{name: "viewport", content: "width=device-width, initial-scale=1"},
]}
/>
<Switch>
<Route exact path='/' component={ Homepage } />
<Route path="/about" component={ About } />
<Route path="/contact" component={ Contact } />
</Switch>
</div>
);
}
}
template.jsx
export default ({ markup, helmet }) => {
return `<!doctype html>
<html ${helmet.htmlAttributes.toString()}>
<head>
${helmet.title.toString()}
${helmet.meta.toString()}
${helmet.link.toString()}
</head>
<body ${helmet.bodyAttributes.toString()}>
<div id="root">${markup}</div>
<div>Heeeeeeeeeeeeeeeeeeeelmet</div>
<script src="/static/client.js" async></script>
</body>
</html>`;
};
menu.jsx:
import { Link } from 'react-router-dom';
import React, { Component } from 'react';
import './menu.scss';
class Menu extends Component {
render() {
return (
<div>
<ul>
<li>
<Link to={'/'}>Homepage</Link>
</li>
<li>
<Link to={'/about'}>About</Link>
</li>
<li>
<Link to={'/contact'}>Contact</Link>
</li>
</ul>
</div>
);
}
}
export default Menu;
.babelrc:
{
"presets": [
"#babel/react",
"#babel/preset-env"
],
"plugins": [
"#babel/proposal-class-properties"
]
}
homepage.sccs
.component {
color: blue;
}
menu.scss:
li {
background-color: yellow;
}
I used this article:
https://blog.digitalkwarts.com/server-side-rendering-with-reactjs-react-router-v4-react-helmet-and-css-modules/
Webpack Community now details an approach for SSR sass compiled via webpack in mini-css-extract-plugin/#recommend
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devMode = process.env.NODE_ENV !== "production";
module.exports = {
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
devMode ? "style-loader" : MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
],
},
plugins: [].concat(devMode ? [] : [new MiniCssExtractPlugin()]),
};
Note that style-loader should not be used in an SSR app or in a webpack production build because injects CSS into the DOM. MiniCSSExtractPlugin is recommended for SSR production builds and should not be used with style-loader (window will not be defined in webpack's node-based prod build).

Use Pure Bootstrap v4 on ReactJs is NOT working

I was desperately want to use pure Bootstrap v4 on my React.js app. I created my app using create-react-app. So, i put Bootstrap assets on index.html (in public folder).
At the first try, it was working well. Then, i added some dependencies like react-router-dom, react-router-config, and prop-types. Suddenly, it displayed almost a blank page.
1) Project Folder
2) kodebaru/webpack.config.js
const path = require('path');
module.exports = {
entry: path.join(__dirname, '/client/src/index.jsx'),
output: {
path: path.join(__dirname, '/client/dist/js'),
filename: 'app.js',
},
module: {
loaders: [
{
test: /\.jsx?$/,
include: path.join(__dirname, '/client/src'),
loader: 'babel-loader',
query: {
presets: ["react", "es2015"]
}
}
]
},
watch: true
};
3) kodebaru/server.js
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.resolve(__dirname, './backend/static/')));
app.use(express.static(path.resolve(__dirname, './client/dist/')));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, './backend/static/', 'index.html'));
});
const PORT = process.env.PORT || 3500;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
4) kodebaru/backend/static/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Kodebaru</title>
<link rel="stylesheet" href="./bootstrap/bootstrap.min.css">
</head>
<body>
<div id="root"></div>
<script src="/js/app.js"></script>
</body>
</html>
5) result
6) Warning Message
I knew there is a framework bootstrap for react app (reactstrap). But, this time i want to know how to use pure bootstrap v4 in react app ?
It is too late. But, i think it is good to answer my own question since there is no one. The solution was to install bootstrap using npm, import bootstrap on index.jsx, add jQuery, Popper.js, and css loader on webpack configuration file.
a) Install bootstrap using npm
npm install bootstrap#4.0.0-beta
b) Import bootstrap on index.jsx
import 'bootstrap';
require('bootstrap/dist/css/bootstrap.css');
c) Add jQuery and Popper.js on webpack
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default']
})
d) Add css loader on webpack
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
The full implementation is below :
1) index.jsx
import React from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from "redux";
import promise from "redux-promise";
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { renderRoutes } from 'react-router-config';
import routes from './routes.js';
import reducers from './redux/reducers/index.js'
import 'bootstrap';
require('bootstrap/dist/css/bootstrap.css');
const createStoreWithMiddleware = createStore(reducers, {}, compose(applyMiddleware(promise)));
ReactDOM.render(
<Provider store = {createStoreWithMiddleware}>
<Router>
{/* kick it all off with the root route */}
{renderRoutes(routes)}
</Router>
</Provider>,
document.getElementById('root')
);
if(module.hot) {
module.hot.accept('./routes.js', function() {
routes();
})
}
2) webpack.config.js
const webpack = require('webpack');
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './app/index.js',
output: {
filename: 'index_bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.join(__dirname, '/app'),
exclude: '/node_modules',
loader: 'babel-loader',
query: {
presets: ["react", "es2015"],
plugins: [
"transform-react-pug",
"transform-react-jsx",
"transform-object-rest-spread"
]
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default']
}),
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './index.html'
})
],
devtool: 'cheap-module-eval-source-map',
watch: true
};

Resources