React component not rendering correctly after await call - javascript

i have html template i purchased at themeforest.net im trying to convert it to webpack and react every thing works fine now but there is weird bug when ever i make await call in componentDidMount the page didnt render correctly
let res = await axios({
method: "get",
url: "http://localhost:8080/api/main/mainProducts",
});
this.setState({ allProducts: res.data });
when i comment the await call
and setstate to static data
let allProducts = [
{
//array data
},
]
this.setState({ allProducts: allProducts });
its render correctly. here is the component
export class MainComponent extends React.Component<{}, any> {
constructor(props) {
super(props);
this.state = {
allProducts: [],
};
}
async componentDidMount() {
let res = await axios({
method: "get",
url: "http://localhost:8080/api/main/mainProducts",
});
this.setState({ allProducts: res.data });
}
render(): any {
return (
<div className="product-4 product-m no-arrow">
{this.state.allProducts.map((x) => (
<div key={x.id} className="product-box product-wrap">
<div className="img-wrapper">
<div className="lable-block">
<span className="lable3">new</span>{" "}
<span className="lable4">on sale</span>
</div>
<div className="front">
<a href={"/product/" + x.id}>
{x.images.map((image) =>
image.main.toString() === "true" ? (
<img
className="img-fluid blur-up lazyload bg-img"
key={image.id}
src={`/public/productImages/${x.id.toString()}/${
image.imageName
}`}
></img>
) : (
""
)
)}
</a>
</div>
</div>
</div>
))}
</div>
// long html lines here
// ...
);
}
}
webpack config
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: path.join(__dirname, "src/index.tsx"),
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(svg|gif|jpg|png|eot|woff|woff2|ttf)$/,
use: [
'url-loader',
],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
{
test: /\.tsx?$/,
loader: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.ts$/,
use: ["ts-loader"],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src", "index.html"),
filename: "./index.html",
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
}),
],
output: {
path: __dirname + "/dist/",
filename: "index.js",
publicPath: '/'
},
devServer: {
historyApiFallback: true,
proxy: {
"/api": {
target: "http://localhost:5050",
pathRewrite: { "^/api": "" },
},
},
},
mode: "development",
};
entry point index.tsx
import React from "react";
import { render } from "react-dom";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { MainComponent } from "./views/user/main/main";
import { Bottom } from "./views/user/layout/bottom";
import { Top } from "./views/user/layout/top";
import "core-js/stable";
import "regenerator-runtime/runtime";
import "./helpers/css"; //css imports of the html template
render(
<Router>
<Switch>
<Route path="/" exact>
<>
<Top />
<MainComponent />
<Bottom />
</>
</Route>
</Switch>
</Router>,
document.getElementById("r")
);
import "./helpers/js"; //js imports of the html template
and most importantly css and js imports
css.tsx
import "/public/assets/css/fontawesome.css";
import "/public/assets/css/slick.css";
import "/public/assets/css/slick-theme.css";
import "/public/assets/css/animate.css";
import "/public/assets/css/themify-icons.css";
import "/public/assets/css/bootstrap.min.css";
import "/public/assets/css/bootstrap4-toggle.min.css";
import "/public/assets/css/jquery.lazyloadxt.spinner.css";
import "/public/assets/css/color5.css";
import "/public/assets/css/site.css";
js.tsx
import "/public/assets/js/jquery-ui.min.js";
import "/public/assets/js/jquery.exitintent.js";
import "/public/assets/js/exit.js";
// #ts-ignore
window.Popper = require("/public/assets/js/popper.min.js");
import "/public/assets/js/slick.js";
import "/public/assets/js/menu.js";
import "/public/assets/js/lazysizes.min.js";
import "/public/assets/js/bootstrap.min.js";
import "/public/assets/js/bootstrap4-toggle.min.js";
import "/public/assets/js/bootstrap-notify.min.js";
import "/public/assets/js/fly-cart.js";
import "/public/assets/js/script.js";
import "/public/scripts/layout.js";
i suspect its something to do with slick library
ive tried import() slick js and css files after setstate but it doesnt work
this.setState({ allProducts: res.data }, () => {
import("../../../../public/assets/css/slick.css");
import("../../../../public/assets/css/slick-theme.css");
import("../../../../public/assets/js/slick.js");
});
i have also tried re import the whole css and js files but also doesnt work
i have also tried many other things like using ajax instead of axios but it give the exact same bug ive also tried this
axios({
method: "get",
url: "http://localhost:8080/api/main/mainProducts",
}).then((x) => {
this.setState({ allProducts: x.data });
});
no await here but its same bug also.
a picture of when its render correctly
wrong render
any help would be really appreciated.
thanks !

Related

HMR not triggering sometimes for components

This has been baffling me for a few hours now & I can't seem to work out why. My project structure is below. Sometimes a change in views/Dashboard/index.jsx will trigger a hot reload & other times it will not. It's weird but when it works, after about an hour or so, it will just suddenly stop working...
index.js
import 'react-hot-loader'
import 'bootstrap/dist/css/bootstrap.min.css'
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import { library } from '#fortawesome/fontawesome-svg-core'
import { faChartBar, faThList, faCogs, faClipboard, faFilter, faNotEqual } from "#fortawesome/free-solid-svg-icons"
import configureStore, { history } from './redux/store'
import App from './App'
library.add(faChartBar, faThList, faCogs, faClipboard, faFilter, faNotEqual)
let store
function render(Component) {
ReactDOM.render(
<AppContainer>
<Component store={store} />
</AppContainer>,
document.getElementById('root')
)
}
configureStore()
.then(_store => {
store = _store
render(App)
if (module.hot) {
// Reload components
module.hot.accept('./App', () => {
render(App)
})
}
})
.catch(err => {
console.log(err)
})
App.jsx
import { hot } from 'react-hot-loader/root'
import React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter as Router } from 'react-router-dom'
import PropTypes from 'prop-types'
// Routes
import routes from './routes'
const App = ({ store }) => {
return (
<Provider store={store}>
<Router>{routes}</Router>
</Provider>
)
}
App.propTypes = {
history: PropTypes.object,
}
export default hot(module)(App)
routes/index.js
import React from 'react'
import { Route, Switch } from 'react-router'
// Components
import Dashboard from '../views/Dashboard'
// Views
import NoMatch from '../views/NoMatch'
export default (
<Switch>
<Route path="/" component={Dashboard} exact={true} />
<Route component={NoMatch} />
</Switch>
)
views/Dashboard/index.jsx
import React, { Component } from 'react'
export default class Dashboard extends Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
Hello World
</div>
)
}
}
If I make any change to the first 4 files listed (index.js, App.jsx, routes/index.js, containers/Dashboard.js) then the hot reloading works & the page is reloaded. However, if I attempt to make a change to views/Dashboard/index.jsx, for example, change "Hello World" to "Foo Bar" then the hot reloading is not honoured.
However I have now taken out the intermediary step of redux & changed the routers/index.js to use the direct component from views/Dashboard/index.jsx & it still does not reload.
How can this be? If I set the component on the Route to the container listed above, it hot reloads for that file but not this JSX one? Is this to do with the structure inside my main component views/Dashboard/index.jsx? If so, what? As it looks fine to me.
EDIT
My complete webpack config is:
webpack.common.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const DotenvPlugin = require('dotenv-webpack')
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
filename: 'js/[name].bundle.js',
},
resolve: {
extensions: ['.js', '.jsx'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader', // Using Babel to compile JS files
},
{
test: /\.(css|scss|sass)$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(png|svg|jpg|gif|woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1000000,
name: 'img/[hash].[ext]',
},
},
],
},
{
test: /\.html$/,
loader: 'html-loader'
}
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public', 'index.html'),
filename: './index.html',
}),
new DotenvPlugin({
systemvars: true,
}),
],
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
}
webpack.dev.js
const webpack = require('webpack')
const merge = require('webpack-merge')
const path = require('path')
const common = require('./webpack.common.js')
module.exports = merge(common, {
mode: 'development',
entry: path.resolve(__dirname, 'src', 'index.js'),
// https://github.com/gaearon/react-hot-loader#source-maps
devtool: 'eval',
devServer: {
contentBase: path.join(__dirname, 'dist'),
open: true,
compress: true,
hot: true,
historyApiFallback: true
},
resolve: {
alias: {
'react-dom': '#hot-loader/react-dom'
}
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
],
optimization: {
usedExports: true,
},
})
.babelrc
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": "3.0.0",
"targets": {
"esmodules": true
}
}
],
"#babel/preset-react"
],
"plugins": [
"react-hot-loader/babel"
]
}
I have updated the files listed to show what I currently have. This is a very weird error as sometimes the hot reloading will work & other times it will not. Hot reloading always works for files; index.js, App.jsx, & routes/index.jsx but sometimes it will work for views/Dashboard/index.jsx & sometimes it will not.
I was previously following the Getting Started guide but this thread helped me realise this was out of date. I have now just followed the README as is mentioned. I have also attempted to take snippets from this article as well on setting up HMR with Webpack 4.
Versions
webpack: 4.41.6
webpack-dev-server: 3.10.3
babel-loader: 8.0.6
#hot-loader/react-dom: 16.11.0
react: 16.12.0
react-hot-loader: 4.12.19
I have the below response in the console so HMR is clearly enabled
I am trying to replicate exactly what is in the examples as recommended

Storybook + MDX

My .js stories show perfectly on storybook but .mdx stories do not show & I get no error as well
main.js
module.exports = {
addons: [
'#storybook/addon-docs/register',
'#storybook/addon-actions/register',
'#storybook/addon-links/register',
'#storybook/addon-knobs/register',
'#storybook/addon-storysource/register',
'#storybook/addon-viewport/register',
],
};
webpack.config.js
as suggested here https://www.npmjs.com/package/#storybook/addon-docs#manual-configuration
config.module.rules.push({
test: /\.(stories|story)\.mdx?$/,
use: [
{
loader: 'babel-loader',
options: {
plugins: ['#babel/plugin-transform-react-jsx'],
},
},
{
loader: '#mdx-js/loader',
options: {
compilers: [createCompiler({})],
},
},
],
});
config.module.rules.push({
test: /\.(stories|story)\.jsx?$/,
loader: require.resolve('#storybook/source-loader'),
exclude: [/node_modules/],
enforce: 'pre',
});
preview.js
addParameters({
docs: {
container: DocsContainer,
page: DocsPage,
},
});
function loadStories() {
const requires = [require.context('#rrc', true, /\.stories\.(js|mdx)$/)];
for (const req of requires) req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
Now I have 2 types of stories
story.mdx
import { Meta, Story } from '#storybook/addon-docs/blocks';
// Components
import Chips from '../';
<Meta title="AAAAAAAAA AAAAAA/Chip2" component={Chip} />
# Chip
I can define a story with the function imported from CSF:
And I can also embed arbitrary markdown & JSX in this file.
<Chip label="Basic" />
<Preview>
<Story name="all checkboxes">
<form>
<Chip label="Basic" />
</form>
</Story>
</Preview>
### Installing
A step by step series of examples that tell you how to get a development env running
and .js stories which are like
import React from 'react';
import { storiesOf } from '#storybook/react';
import { Chip } from '../../..';
storiesOf('Chip', module)
.addParameters({
component: Chip,
})
.add('Basic', () => <Chip label="Basic" />)
.add('Disabled', () => <Chip label="Disabled" disabled />)

Why does isomorphic-style-loader throw a TypeError: Cannot read property 'apply' of undefined when being used in unison with CSS-Modules

I'm currently trying to render the application on the server, which works for the HTML and JS, but found that my styles (.less | .scss) would not load. I did some research and figured, not sure, that I was missing the isomorphic-style-loader in my Webpack configuration based on others running into the same issues. I set it up, at least how I understood it, but am now finding that when running the application I receive the following error:
TypeError: Cannot read property 'apply' of undefined at WithStyles.componentWillMount
I'm somewhat new to the whole React / Express thing but have been trying to follow along with tutorials and learning as I go, if anything seems out of place, please excuse me. I am hoping to see if anybody can explain what exactly causes this error, and provide me with some idea of what I could follow to resolve this error. Below is some example code that resembles the one I am having issues with, if it helps in any way.
(For reference I was following Tyler McGinnis React Router Server Rendering tutorial and tried to expand upon it to add styling - Link Here)
Thanks beforehand for any explanation provided as to what may be causing this error.
webpack.config.babel.js
import path from 'path'
import webpack from 'webpack'
import nodeExternals from 'webpack-node-externals'
const paths = {
browser: path.join(__dirname, './src/browser'),
server: path.join(__dirname, './src/server'),
build: path.resolve(__dirname, 'public')
}
let browserConfig = {
entry: `${paths.browser}/index.js`,
output: {
path: paths.build,
filename: 'bundle.js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.s?(a|c)ss$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.less$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
}
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true
}
},
'postcss-loader'
]
}, {
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [
new webpack.DefinePlugin({
__isBrowser__: true
})
],
resolve: {
extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.sass', '.less']
}
}
let serverConfig = {
entry: `${paths.server}/index.js`,
target: 'node',
externals: [nodeExternals()],
output: {
path: __dirname,
filename: 'server.js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.s?(a|c)ss$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.less$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
}
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true
}
},
'postcss-loader'
]
}, {
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [
new webpack.DefinePlugin({
__isBrowser__: false
})
],
resolve: {
extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.sass', '.less']
}
}
module.exports = [browserConfig, serverConfig]
server.js
import express from "express"
import cors from "cors"
import React from "react"
import bodyParser from 'body-parser'
import serialize from "serialize-javascript"
import { renderToString } from "react-dom/server"
import { StaticRouter, matchPath } from "react-router-dom"
import App from '../shared/App'
import routes from '../shared/routes'
const app = express()
const port = process.env.PORT || 3000
app.use(cors())
app.use(bodyParser.json()) // support json encoded bodies
app.use(bodyParser.urlencoded({extended: true})) // support encoded bodies
app.use(express.static("public"))
app.get("*", (req, res, next) => {
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
const promise = activeRoute.fetchInitialData
? activeRoute.fetchInitialData(req.path)
: Promise.resolve()
promise.then((data) => {
const css = new Set()
const context = { data, insertCss: (...styles) => styles.forEach(style => css.add(style._getCss())) }
const markup = renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
)
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>React on the Server!</title>
<script src="/bundle.js" defer></script>
<script>window.__INITIAL_DATA__ = ${serialize(data)}</script>
</head>
<body>
<div id="app">${markup}</div>
</body>
</html>
`)
}).catch(next)
})
app.listen(port, () => console.log(`Server is listening on port: ${port}`))
routes.js
import AboutMain from './components/About/AboutMain'
const routes = [
{
path: '/about',
component: AboutMain
}
]
export default routes
browser.js
// Import the neccessary modules for use in file
import React from 'react' // Main React module
import { hydrate } from 'react-dom' // render alternative for server rendering
import App from '../shared/App'
import { BrowserRouter } from 'react-router-dom' // React Router component for client side routing
import '../shared/components/global.scss' // Only has general rules, which do get applied
hydrate(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('app')
)
App.js
import React, { Component } from 'react'
import routes from './routes'
import { Route, Link, Redirect, Switch } from 'react-router-dom'
class App extends Component {
render() {
return (
<div>
<Switch>
{routes.map(({ path, exact, component: Component, ...rest }) => (
<Route key={path} path={path} exact={exact} render={(props) => (
<Component {...props} {...rest} />
)} />
))}
<Route render={(props) => <NoMatch {...props} /> } />
</Switch>
</div>
)
}
}
export default App
AboutMain.js
// Importing Required Modules
import React, {Component, Fragment} from 'react' // Importing React, Component, Fragment from "react"
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './about.scss'
class AboutMain extends Component {
state = {
phrase: 'We Made It!'
}
render() {
return (
<Fragment>
<header className={s.banner}>
<h1 className={s.heading}>{this.state.phrase}</h1>
</header>
</Fragment>
)
}
}
export default withStyles(s)(AboutMain) <-- Error Seems to occur here, at least I think.
about.scss
.banner {
margin: 0 auto;
padding: 15px;
border: 2px solid #000;
}
.heading {
text-transform: uppercase;
text-decoration: underline;
}
The problem went away simply because you removed isomorphic-style-loader. Please don't accept your own answer like that. The problem here is you did not provide a context so insertCss.apply(_context, styles) will complain because _context is undefined. To solve the problem, follow these steps:
Create a ContextProvider component in the same directory of App
ContextProvider.js
import React from 'react';
import PropTypes from 'prop-types'
import App from './App'
class ContextProvider extends React.Component {
static childContextTypes = {
insertCss: PropTypes.func,
}
getChildContext() {
return { ...this.props.context }
}
render () {
return <App { ...this.props } />
}
}
export default ContextProvider
Wrap the ContextProvider in BOTH your browser.js and server.js. Remember to declare the context in both files.
browser.js (in other apps, this would be root client code, i.e client.js or index.js)
// Import the neccessary modules for use in file
/* import statements */
const context = {
insertCss: (...styles) => {
const removeCss = styles.map(x => x._insertCss());
return () => {
removeCss.forEach(f => f());
};
},
}
hydrate(
<BrowserRouter>
//ContextProvider wraps around and returns App so we can do this
<ContextProvider context={context} />
</BrowserRouter>,
document.getElementById('app')
)
server.js
//Additional code above
app.get("*", (req, res, next) => {
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
const promise = activeRoute.fetchInitialData
? activeRoute.fetchInitialData(req.path)
: Promise.resolve()
promise.then((data) => {
const css = new Set()
const context = { insertCss: (...styles) =>
styles.forEach(style => css.add(style._getCss()))}
const markup = renderToString(
<StaticRouter location={req.url}>
<ContextProvider context={context}>
<App />
</ContextProvider>
</StaticRouter>
)
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>React on the Server!</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(port, () => console.log(`Server is listening on port: ${port}`))
I wrote an article explaining this in more detail here: https://medium.com/#danielnmai/load-css-in-react-server-side-rendering-with-isomorphic-style-loader-848c8140a096
After reviewing the code all night and endlessly searching Google. I found a fix that the main issue with my code was in the webpack.config.babel.js setup.
I changed the browser test for sass || scss to use style-loader, rather than the isomorphic-style-loader. I also removed all isomorphic-style-loader logic from my app (ie. withStyles, insertCss, etc.)
I'm not sure if this was the correct approach, but for the meantime, it seems to fix my problem and does not return any errors or network issues.

React-hot-loader not re-rending components

I have an application that is serving an EJS view with my React.js bundle loaded in a script tag.
I have followed the instructions for react-hot-loader v3 and #next, neither are working. The are no errors in the console and the components are not being re-rendered on change.
Here is my app entry point:
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { AppContainer } from 'react-hot-loader'
import { store } from './routes';
import App from './containers/App';
const render = Component => {
ReactDOM.render(
<Provider store={store}>
<MuiThemeProvider>
<AppContainer>
<Component />
</AppContainer>
</MuiThemeProvider>
</Provider>,
document.getElementById('root'))
};
render(App);
//registerServiceWorker();
// Webpack Hot Module Replacement API
if (module.hot) {
console.log('module.hot exists');
module.hot.accept('./containers/App', () => {
console.log('Reloading app');
render(App);
})
}
Here is the App files that the entry point is calling:
import React from 'react';
import Navigation from '../components/Navigation';
import { hot } from 'react-hot-loader'
import createRoutes from '../routes';
const routes = createRoutes();
const App = () => {
return ([
<Navigation key="app-navigation" />,
<main style={{ height: 'calc(100% - 85px)' }} key="app-main">{routes}</main>
])
};
export default hot(module)(App)
Here is my webpack dev config:
const devBrowserRender = {
devtool: 'source-map',
context: PATHS.app,
entry: {
app: ['babel-polyfill', 'react-hot-loader/patch',
'./index']
},
node,
devServer: {
contentBase: PATHS.assets,
hot: true
},
output: {
path: PATHS.assets,
filename: '[name].dev.js',
publicPath: PATHS.public
},
module: { rules: rules({ production: false, browser: true }) },
resolve,
plugins: plugins({ production: false })
};
Here are my JavaScript rules:
const presets = [["es2015", { "modules": false }], 'react', 'stage-0'];
const plugins = production ? [
'transform-react-remove-prop-types',
'transform-react-constant-elements',
'transform-react-inline-elements'
] : [];
return {
test: /\.js$|\.jsx$/,
loader: 'babel-loader',
options: {
presets,
plugins
},
exclude: PATHS.modules
};
Developer plugins:
if (!production) {
return [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.EnvironmentPlugin(['NODE_ENV']),
new webpack.DefinePlugin(compileTimeConstantForMinification),
new ExtractTextPlugin({
filename: '[contenthash].css',
allChunks: true
}),
// new webpack.optimize.UglifyJsPlugin({ compress }),
new ManifestPlugin({
fileName: 'manifest.json'
})
];
}
I'm assuming this is coming from a misunderstanding about how react-hot-loader works, but I cannot find any other information about why it wouldn't work in the docs or examples.
I know the pain of configuring this stuff.
You need to include the next lines in your entry section
entry: {
app: [
'react-hot-loader/patch',
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./index.js'
]
}
then when you are setting babel-loader configuration you need to add react-hot-loader/babel
const plugins = production ? [
'transform-react-remove-prop-types',
'transform-react-constant-elements',
'transform-react-inline-elements'
] : ['react-hot-loader/babel'];
Here I have a simple configuration with this feature.
Hope it helps.

React static site with webpack

I'm trying to create a static site following this tutorial http://jxnblk.com/writing/posts/static-site-generation-with-react-and-webpack/
I'm currently getting this error: ERROR in ReferenceError: document is not defined
This is my app.jsx file:
import React from 'react';
import ReactDOM from 'react-dom';
import { Router } from 'react-router';
import routes from './config/routes';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<Router>{routes}</Router>
);
}
}
export default App;
module.exports = function render(locals, callback) {
var html = React.renderToStaticMarkup(React.createElement(App, locals))
callback(null, '<!DOCTYPE html>' + html)
}
Routes:
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import Layout from '../components/layout';
import Home from '../components/home';
export default (
<Route path="/" component={Layout}>
<IndexRoute component={Home} />
</Route>
);
layout.jsx component:
import React from 'react';
import Nav from './nav';
import Footer from './footer';
import Styles from '../styles.scss';
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div id="layout" className={Styles.main}>
<Nav />
{this.props.children}
<Footer />
</div>
)
}
}
Layout.PropTypes = {
children: React.PropTypes.object.isRequired
}
export default Layout;
and my webpack.config.js file:
/* eslint-disable */
var path = require('path'),
webpack = require('webpack'),
autoprefixer = require('autoprefixer'),
OpenBrowserPlugin = require('open-browser-webpack-plugin');
StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
data = require('./data');
var configServe = {
port: 9100,
};
module.exports = {
devServer: {
hot: true,
inline: true,
historyApiFallback: true,
progress: true,
port: configServe.port,
},
entry: [
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:' + configServe.port,
path.resolve(__dirname, './src/app.jsx'),
],
output: {
path: __dirname,
filename: './dist/bundle.js',
libraryTarget: 'umd'
},
module: {
loaders: [
{
// JSX files :
test: /\.js[x]?$/,
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react',
},
{
// CSS files :
test: /\.css?$/,
include: path.resolve(__dirname, 'src'),
loader: 'style-loader!css-loader!postcss-loader',
},
{
// SCSS files :
test: /\.scss?$/,
include: path.resolve(__dirname, 'src'),
loader: 'style-loader!css-loader!postcss-loader!sass',
},
{
test: /\.(png|jpg)$/,
include: path.resolve(__dirname, 'src'),
loader: 'file-loader'
},
{
test: /\.svg$/,
loader: 'svg-inline'
}
],
},
postcss: [
autoprefixer({ browsers: ['last 3 versions'] }),
],
plugins: [
// Avoid publishing files when compilation fails
new StaticSiteGeneratorPlugin('./dist/bundle.js', data.routes, data),
new webpack.NoErrorsPlugin(),
new webpack.HotModuleReplacementPlugin(),
new OpenBrowserPlugin({ url: 'http://localhost:' + configServe.port }),
],
resolve: {
extensions: ['', '.js', '.jsx'],
},
stats: {
// Nice colored output
colors: true,
},
// Create Sourcemaps for the bundle
devtool: 'source-map',
};
Hopefully someone can help me figure this out. I'd like to eventually bundle this all in a non-opinionated way of creating static webpages with React and posting on github.
I guess this line is causing error:
var html = React.renderToStaticMarkup(React.createElement(Root, locals))
There you are using some Root component, but concluding from your code it is not defined. Also it is defined in tutorial (you have pointed out) by this line: var Root = require('./components/Root.jsx')

Categories

Resources