Import JSX file into webpack config - javascript

I am trying to import a JSX file into my webpack config. It appears the file imports, but I cannot import modules into that file. I continuously get an error saying Cannot use import statement outside a module
Here is my webpack.config.js:
const bodyParser = require('body-parser')
require('#babel/register')
const render = require('../src/static/render.jsx')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const path = require('path');
const PATHS = {
app: path.join(__dirname, '../src/static'),
build: path.join(__dirname, '../src/static_dist')
};
const basePath = path.resolve(__dirname, '../src/static/');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
output: {
filename: '[name].js',
path: PATHS.build,
publicPath: '/static/'
},
devServer: {
before: function(app) {
app.use(bodyParser.json({ limit: '10mb' }))
app.post('/render', function (req, res) {
res.sendStatus(204);
const initialState = {} //buildInitialState(req.body)
const result = render(url, initialState)
res.json({
html: result.html,
finalState: result.finalState
})
});
},
// Render.jsx
require('#babel/register');
import React from 'react' <-- error happens here
import { Provider } from 'react-redux'
import { match, RouterContext } from 'react-router'
import ReactDOMServer from 'react-dom/server'
import configureStore from './store/configureStore';
import { createBrowserHistory } from "history";
import { routes } from "../routes.js";
import AdminNavbar from "./components/Navbars/AdminNavbar.jsx";
import Sidebar from "./components/Sidebar/Sidebar.jsx";
export default function render (url, initialState) {
... a function ...
}
I feel like I have tried everything! Tinkering with babel, adding #babel/register, adding a .babelrc, changing how it is imported, etc.

You likely need to tell Webpack to resolve that particular extension.
Here's the documentation on resolve: Resolve
The code:
module.exports = {
//...
resolve: {
extensions: ['.js', '.jsx']
}
};
Also I notice you haven't specified your entry. If the solution above doesn't work, try specifying the following:
module.exports = {
//...
entry: './src/Render.jsx'
};
Docs: Entry Point
You likely have to do both.

Related

Move index.html from dir in root dir (vite)

How can i made a move index.html from src/pages/index/index.html to dist/index.html and src/pages/donate/index.html to dist/pages/donate/index.html at a build vite project?
My vite.config.js
import { resolve } from 'path';
import { defineConfig } from 'vite';
const root = resolve(__dirname, 'src');
const outDir = resolve(__dirname, 'dist');
export default defineConfig({
root,
build: {
outDir,
emptyOutDir: true,
rollupOptions: {
input: {
main: resolve(root, 'pages/index/index.html'),
donate: resolve(root, 'pages/donate/index.html')
}
}
}
})
You'll need to use the rollup options in your vite config file.
Something like this should get you going in the right direction:
import { defineConfig } from 'vite';
import { resolve } from 'path';
import path from "path";
export default {
root: path.resolve(__dirname, "src"),
build: {
outDir: path.resolve(__dirname, "dist"),
rollupOptions: {
input: {
index: path.resolve(__dirname, "src/pages/index/index.html"),
donate: path.resolve(__dirname, "src/pages/donate/donate.html"),
},
},
},
};

window is not defined server side rendering(react + express)

If the browser URL is requested, routing works normally.
By the way, location = ${path};
The part that says Component An error occurs when calling react renderToString function.
I'm looking at web pack settings or something, but I can't find the cause. Help!
// App.js
import React, {useState, useEffect} from 'react';
import moment from "moment";
import Header from "./components/header/Header";
import Footer from "./components/footer/Footer";
export default function App() {
const [time, setTime] = useState(null);
useEffect(() => {
console.log('use effect..');
setTime(moment().format('hh:mm:ss a'));
}, []);
return (
<div style={{height:'100%'}}>
<Header/>
<div style={{height:'100%'}}>
<h1>Sample App</h1>
<p>Current time is {time}</p>
</div>
<Footer/>
</div>
)
}
// Header.js
import React from 'react';
export default function Header() {
function goPage(path) {
console.log(`goPage..`);
console.log(window.location); // error
// window.location = path;
}
return (
<header style={{width: '100%', border: '1px dotted black'}}>
<div>
<span style={{padding: '4px'}}>My App |</span>
<span style={{padding: '4px', cursor: 'pointer'}}>Home</span>
<span style={{padding: '4px', cursor: 'pointer'}} onClick={goPage('/about')}>About</span>
</div>
</header>
)
}
server.js
const express = require('express');
const path = require('path');
import React from 'react';
import ReactDOMServer from 'react-dom/server';
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('../webpack.config.js');
const compiler = webpack(config);
import Router from '../routes/index';
import App from '../src/App';
import Html from "../src/Html";
const expressApp = express();
const port = process.env.PORT || 3000;
if (process.env.NODE_ENV != 'production') {
expressApp.use(webpackDevMiddleware(compiler, {
publicPath: '/'
}));
}
expressApp.use(express.static(path.join(__dirname, '')));
expressApp.get('*', (request, response) => {
console.log('request.. in express');
console.log(Router.match(request));
const component = ReactDOMServer.renderToString(Router.match(request));
const html = ReactDOMServer.renderToStaticMarkup(<Html
title="Sample Title"
description="Isomorphic web application sample"
body={component}
/>);
response.send(`<!DOCTYPE html>` + html);
});
expressApp.listen(port, () => {
console.log(`App is listening at http://localhost:${port}/`);
});
// Router
import React from 'react';
import App from "../src/App";
import NotFound from "../src/components/error/NotFound";
import Error from "../src/components/error/Error";
import About from "../src/components/about/About";
const routes = [
{name : 'home', path : '/', action : () => <App/>},
{name : 'about', path : '/about', action : () => <About/>},
{name : '404', path : '/404', action : () => <NotFound/>},
{name : '500', path : '/500', action : () => <Error/>},
];
export default {
match(location) {
console.log(location.path);
const route = routes.find(x => x.path === location.path);
if (route) {
try {
return route.action();
} catch (err) {
console.log('err');
return routes.find(x => x.path === '/500').action();
}
} else {
console.log('404');
return routes.find(x => x.path === '/404').action();
}
}
}
// webpack config
const path = require('path');
// plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
// SSR
const ssr = {
mode : 'development',
entry: './server/server.js',
output: {
path: path.join(__dirname, '/build'),
filename: "server.js",
},
target: 'node',
node: false,
externals: [nodeExternals()],
resolve: {
modules: ['node_modules']
},
module: {
rules: [
{
test: /(.js|.jsx)/,
exclude: /node_modules/,
include: [
path.join(__dirname, '/src'),
path.join(__dirname, '/routes/index.js'),
path.join(__dirname, '/server/server.js'),
],
use: {
loader: 'babel-loader'
}
},
]
},
plugins: [
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['build']
})
],
};
// CSR
const csr = {
mode : 'development',
entry:'./client/client.js',
output: {
publicPath: '/',
path: path.join(__dirname, '/build'),
filename: 'client.js'
},
target: 'web',
module: {
rules: [
{
test: /(.js|.jsx)/,
exclude: /node_modules/,
include: [
path.join(__dirname, '/src'),
path.join(__dirname, '/routes/index.js'),
path.join(__dirname, '/client/client.js'),
],
use: {
loader: 'babel-loader'
}
},
]
},
// devtool: 'source-map',
plugins: [
new MomentLocalesPlugin({
localesToKeep: ['es-us', 'ru'],
}),
]
};
module.exports = [ssr, csr];
The server is composed of express, and is set to babel7 and webpack4.
If you look at the server.js part, you get the corresponding react component in the request URL.
If renderToString() is called on the obtained component, an error of window is not defined occurs.
I really want to solve it. Please help.
Why window is not defined in SSR
On the ssr there is no definition for window. Because window is a browser based property.
you need to do something to avoid that. e.g
function goPage(path) {
console.log(`goPage..`);
if (window) {
console.log(window.location);
}
}
and on the server side you can get the url by this
req.url
// or
app.get('/users/:userId/books/:bookId', function (req, res) {
console.log(req.params)
}

Default export works on the development site, but returns undefined in Storybook

So I'm building some component stubs for a new project I'm making. To see the visuals for these components I'm using Storybook. I have two separate webpack configs for the Storybook build and the regular build. Both inherit from a base config, shown below (I've removed some irrelevant loaders to make reading easier):
const path = require('path')
const config = {
output: {
filename: '[name].js',
path: path.join(__dirname, 'public/js')
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react'],
plugins: [
'transform-object-rest-spread',
'transform-es2015-destructuring',
["react-css-modules", {
"filetypes": {
".scss": {
"syntax": "postcss-scss",
"plugins": ["postcss-nested"]
}
},
"generateScopedName": "[local]_[hash:base64:5]"
}]
]
}
}
]
},
resolve: {
modules: ['node_modules', path.join(__dirname, 'resources/assets/js')],
}
}
module.exports = config
My Storybook config and my regular config differ like this:
Webpack.config.js
const path = require('path')
const webpack = require('webpack')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const webpackBaseConfig = require(path.join(__dirname, 'webpack.base.config.js'))
const plugins = [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
}),
]
if(process.env.NODE_ENV === 'production') {
plugins.push(new UglifyJSPlugin())
}
const webpackConfig = Object.assign(webpackBaseConfig, {
entry: {
vendor: ['react', 'react-dom', 'react-redux', 'react-router', 'react-router-dom', 'redux-form', 'axios', 'redux'],
app: path.join(__dirname, 'resources/assets/js/app.jsx'),
},
plugins,
})
module.exports = webpackBaseConfig
Webpack.storybook.config.js
const path = require('path')
const webpackBaseConfig = require(path.join(__dirname, '../webpack.base.config.js'))
const storyBookConfig = Object.assign(webpackBaseConfig, {
entry: path.join(__dirname, '../resources/assets/js/app.jsx'),
})
module.exports = storyBookConfig
Now everything works fine when I use the normal build, but when I visit storybook these components seems to break it:
components/AppHeader/AppHeader.component.jsx
import React from 'react'
import { Logo, UserCard } from 'components'
import './AppHeader.scss'
const AppHeader = (props) => {
const { user } = props
return (<div styleName="app-header">
<Logo />
<span styleName="user-profile">
<UserCard firstName={user.firstName} lastName={user.lastName} />
</span>
</div>)
}
export default AppHeader
components/AppHeader/AppHeader.container.jsx
import { connect } from 'react-redux'
import AppHeader from './AppHeader.component.jsx'
const mapStateToProps = (state) => ({
user: state.currentUser,
})
export default connect(
mapStateToProps
)(AppHeader)
The error I get is when exporting the connected component in AppHeader.container.jsx:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in.
So it seems as if the default export in AppHeader.component.jsx is undefined? This is what makes me think that it's a problem with the webpack configuration for Storybook, because the container/component combo works when I view it not in Storybook.
Any suggestions/help would be greatly appreciated, thank you :)

Receiving 404s in my React app despite setting historyApiFallback to true for webpack-dev-server

I'm developing a React application, which is currently served at http://localhost:3000/, and I was hoping to get some basic routing working on it. I've been loosely following the Redux guide however I can't seem to set up a fallback URL correctly. After applying the webpack changes described in the guide, accessing any link such as http://localhost:3000/test results in a 404 response and the "Cannot GET /test" error. The index.jsx file which defines the route looks as follows:
index.jsx
import 'babel-polyfill';
import React from 'react';
import { Router, Route, browserHistory } from 'react-router';
import { createStore, applyMiddleware, compose } from 'redux';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import thunkMiddleware from 'redux-thunk';
import App from './components/App';
import rootReducer from './reducers/';
/* eslint-disable no-underscore-dangle */
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
/* eslint-enable */
const store = createStore(rootReducer, {}, composeEnhancers(
applyMiddleware(thunkMiddleware),
));
if (module.hot) {
module.hot.accept();
}
render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/(:filter)" component={App} />
</Router>
</Provider>,
document.getElementById('root'),
);
Within the webpack config I've tried using historyApiFallback: true as well as historyApiFallback: { index: 'index.html' } and a few variations for the value of the index property. This is the full configuration:
webpack.config.js
var webpack = require('webpack');
var path = require('path');
module.exports = {
debug: true,
devtool: '#eval-source-map',
context: path.join(__dirname, 'src'),
resolve: {
root: path.resolve('./src'),
extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx'],
},
devServer: {
historyApiFallback: {
index: '/',
},
},
entry: [
'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'./index',
],
output: {
path: path.join(__dirname, 'src'),
publicPath: '/',
filename: 'bundle.js',
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
],
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ['react-hot', 'babel'] },
],
},
};
Any ideas for what might be going wrong?
Edit: There's also some BrowserSync configuration which may be related:
app.js
/**
* Require Browsersync along with webpack and middleware for it
*/
var browserSync = require('browser-sync');
var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
/**
* Require ./webpack.config.js and make a bundler from it
*/
var webpackConfig = require('./webpack.config');
var bundler = webpack(webpackConfig);
/**
* Run Browsersync and use middleware for Hot Module Replacement
*/
browserSync({
server: {
baseDir: 'src',
middleware: [
webpackDevMiddleware(bundler, {
// IMPORTANT: dev middleware can't access config, so we should
// provide publicPath by ourselves
publicPath: webpackConfig.output.publicPath,
// pretty colored output
stats: { colors: true },
// for other settings see
// http://webpack.github.io/docs/webpack-dev-middleware.html
}),
// bundler should be the same as above
webpackHotMiddleware(bundler),
],
},
// no need to watch '*.js' here, webpack will take care of it for us,
// including full page reloads if HMR won't work
files: [
'src/css/*.css',
'src/*.html',
],
});
When using browserHistory, you must configure your server appropriately to serve at all routed paths:
https://github.com/ReactTraining/react-router/blob/v2.0.0-rc5/docs/guides/basics/Histories.md#configuring-your-server
But if you don't want to put express server additionally just to make hot reloading work, use this:
webpack-dev-server -d --history-api-fallback --hot --inline --progress --colors
Though I was unable to get browserHistory working in my local dev environment, switching to hashHistory is a good enough fix for the short-term.

App doesn't run when exporting react & react-router to a stand alone html file with webpack

I am trying to export my react SPA to a single html with js so I can install it into a phonegap application.
I have my production "ready" webpack.config however when I export the files everything is bundled up and appears to be ok. But the application stops when it gets to the Provider.
Entry Point - src/client/js/Entry.js
This is the entry point
import React, { Component, PropTypes } from 'react'
import {render} from 'react-dom';
import { Router, browserHistory, Route, IndexRoute } from 'react-router';
import { Provider } from 'react-redux';
import { syncHistoryWithStore } from 'react-router-redux'
import Root from './core/Provider'
import configureStore from './core/Store'
const store = configureStore;
const history = syncHistoryWithStore(browserHistory, store)
console.info('Entry') //OUTPUTS correctly
render(
<Root store={store} history={history} />,
document.getElementById('app')
)
I can confirm that <div id="app"></div> in there on page load.
Provider.js
import React, { Component, PropTypes } from 'react'
import { Provider } from 'react-redux'
import { Router, Route, IndexRoute } from 'react-router'
import App from './App';
//###### Routes #######
import Splash from '../components/pages/Splash';
export default class Root extends Component {
render() {
console.info('Provider'); //Provider Correct
const { store, history } = this.props;
return (
<Provider store={store}>
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={Splash}/>
</Route>
</Router>
</Provider>
)
}
}
Root.propTypes = {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
}
App.js
import React, { Component, PropTypes } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as ActionCreator from '../actions/ActionCreator';
import { browserHistory } from 'react-router'
class App extends Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
}
handleChange(nextValue) {
browserHistory.push(`/${nextValue}`)
}
render() {
console.info('App'); //No console log, does not render
return (
<div>
{this.props.children}
</div>
)
}
}
App.propTypes = {
// Injected by React Router
children: PropTypes.node
}
function mapStateToProps(state, ownProps) {
return {
errorMessage: state.errorMessage,
inputValue: ownProps.location.pathname.substring(1)
}
}
function mapDispatchToProps(dispatch) {
return {
SexAction: bindActionCreators(ActionCreator, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
What I expect when the application is running correctly
What I am seeing with the stand alone app
Store.js
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import createLogger from 'redux-logger'
import rootReducer from './Reducers'
import defaultStates from '../states/statesDefault'
const configureStore = function (preloadedState) {
const Store = createStore(
rootReducer,
preloadedState,
compose(
applyMiddleware(thunk, createLogger())
)
)
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('./Reducers', () => {
const nextRootReducer = require('../../js/Entry').default;
Store.replaceReducer(nextRootReducer)
})
}
return Store;
};
export default configureStore(defaultStates);
Webpack.prod.js
.......
module.exports = {
devtool: 'cheap-module-source-map',
entry: [
path.join(__dirname, 'src/client/js/Entry')
],
output: {
path: path.join(__dirname, '/dist/'),
filename: '[name]-[hash].min.js',
publicPath: './'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new HtmlWebpackPlugin({
template: 'public/index.tpl.html',
inject: 'body',
filename: 'index.html'
}),
new ExtractTextPlugin('[name]-[hash].min.css'),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false,
screw_ie8: true
}
}),
new StatsPlugin('webpack.stats.json', {
source: false,
modules: false
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
],
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ['babel?presets[]=react,presets[]=es2015,presets[]=stage-0'],
include: __dirname
}
......
};
Everything is being exported correctly
[Edit] - Node.js & Express
I realised I have missed out a key bit of information no doubt. I am using node and express. I start my app with npm start
const path = require('path');
const express = require('express');
const webpack = require('webpack');
const webpackMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const config = require('./webpack.config.js');
const isDeveloping = process.env.NODE_ENV !== 'production';
const port = isDeveloping ? 6004 : process.env.PORT;
const app = express();
app.use(express.static(__dirname + '/public/'));
const compiler = webpack(config);
const middleware = webpackMiddleware(compiler, {
publicPath: config.output.publicPath,
contentBase: 'public',
stats: {
colors: true,
hash: false,
timings: true,
chunks: false,
chunkModules: false,
modules: false
}
});
app.use(middleware);
app.use(webpackHotMiddleware(compiler));
app.get('*', function response(req, res) {
res.write(middleware.fileSystem.readFileSync(path.join(__dirname, 'public/index.html')));
res.end();
});
app.listen(port, '0.0.0.0', function onStart(err) {
if (err) {
console.log(err);
}
console.info('==> 🌎 Listening on port %s. Open up http://0.0.0.0:%s/ in your browser.', port, port);
});
We discovered in chat that the issue is incompatibility (at least in Chrome) of the HTML 5 history API with file:// urls. The browserHistory provided by react-router is a wrapper around this. However, for file:// URLs, you can use hashHistory instead:
import { Router, hashHistory, Route, IndexRoute } from 'react-router';
// ...
render(
<Root store={store} history={hashHistory} />,
document.getElementById('app')
)

Categories

Resources