Been at it a couple days...
Trying to use Webpack to do lazy-loading of React modules, app-shell rendered first on the server, then Router injected on the client. It was compiling fine when using gulp, but with Webpack, I get the infamous:
ERROR in ../server/components/routes/AppRouter.jsx
Module parse failed: /web/sites/react-lazy/server/components/routes/AppRouter.jsx Unexpected token (11:6)
You may need an appropriate loader to handle this file type.
AppRouter.jsx:
import React from 'react';
import { Router, Route, IndexRoute } from 'react-router';
import routes from './AppRoute.jsx';
import createMemoryHistory from 'history/lib/createMemoryHistory';
if (typeof require.ensure !== 'function') require.ensure = (d, c) => c(require)
export default class AppRouter extends React.Component {
render() {
return (
<Router routes={routes} history={createMemoryHistory()} /> // < -- errors here
);
}
}
My webpack.config.js:
var path = require('path')
module.exports = {
context: __dirname + "/src",
entry: './js/app.es6.js',
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
include: path.resolve(__dirname, 'src/js'),
exclude: /(node_modules)/,
query: {
presets: ["es2015", "stage-0", "react"],
}
}
]
},
output: {
path: __dirname + '/build',
publicPath: '/build',
filename: 'app.js',
chunkFilename: '[id].chunk.js',
}
}
My directory structure:
/
webpack.config.js
.babelrc
/src
/js
app.es6.js
.babelrc // <-- also put a .babelrc here in case
My package.json:
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.14.0",
"babel-loader": "^6.2.5",
"babel-preset-es2015": "^6.14.0",
"babel-preset-react": "^6.11.1",
"babel-preset-stage-0": "^6.5.0",
"babel-register": "^6.14.0",
"webpack": "^1.13.2",
...
}
I've tried:
duplicating the .babelrc file into the main directory and entry point directory, not sure which is necessary.
registering
babel-register: in app.es6.js:
require('babel-register')({
presets: [ 'es2015', 'stage-0', 'react' ]
});
runnning webpack with '--config webpack.config.js' argument
If I downgrade the babel, babel-core, and babel-loader version to 5.* (from 6.*), there is a different error:
ERROR in ./js/app.es6.js
Module build failed: ReferenceError: [BABEL] /web/sites/react-lazy/src/js/app.es6.js: Unknown option: direct.presets
I'm fairly new to React and webpack, I should say. Anyone know any other tricks?
Solution:
webpack config's 'include' property must include all directories you need to pass through loaders
Your entry file uses components that are located here:
/web/sites/react-lazy/server/components/
However, your include configuration only allows files below /web/sites/react-lazy/src/js/ to be passed to the loader (include means: "any files that should be passed to this loader must be located in this directory").
So either remove the include configuration, or make it an array that also includes the other locations where .jsx files can be found.
Related
I'm writing a React component library which I want to use in other projects without much overhead ( bit, create-react-library, generact, etc. ) and without publishing. I want to use npm install ../shared_lib to add it to my project as a symlink in /node_modules. This command adds the symlink to project node_modules. In my shared_lib I just have a test to export default a <div></div>:
import React from 'react';
const TryTest = function() {
return (
<div>
TryTest
</div>
)
}
export default TryTest;
The problem I'm facing is the following error when I import the component into my working project:
import TryTest from 'shared_lib';
Error:
ERROR in ../shared_lib/src/index.js 6:4
Module parse failed: Unexpected token (6:4)
You may need an appropriate loader to handle this file type.
| const TryTest = function() {
| return (
> <div>
| TryTest
| </div>
# ./src/App.js 27:0-33 28:12-19
# ./src/index.js
# multi babel-polyfill ./src/index.js
If I import anything from shared_lib other than a file with jsx - for example, a string or a function, etc. - it works fine.
EDIT: the application webpack has resolve object's symlinks prop set to false:
resolve: {
symlinks: false
},
EDIT: After applying the solution in the answer below (https://stackoverflow.com/a/60980492/3006493), I later changed symlinks prop back to true. I didn't need to set it to false for the solution to work and render shared_lib components.
My app's loader:
{
test: /\.jsx?$/,
include: [
path.join( __dirname, 'src'), // app/src
fs.realpathSync(__dirname + '/node_modules/shared_lib'), // app/node_modules/shared_lib/dist/shared_lib.js
],
exclude: /node_modules/,
use: [ 'babel-loader' ]
}
EDIT: When I applied the solution in the answer below, the loader now looks like this:
{
test: /\.jsx?$/,
include: [
path.join( __dirname, 'src'), // app/src
fs.realpathSync(__dirname + '/node_modules/shared_lib'), // app/node_modules/shared_lib/dist/shared_lib.js
],
exclude: /node_modules/,
use: [ {
loader: 'babel-loader',
options: require("./package.json").babel
}
]
}
App's current .babelrc settings (I also tried removing .babelrc and including the presets in package.json with same result):
{
"presets": [ "#babel/preset-react", "#babel/preset-env"]
}
**EDIT: After applying the solution in the answer below, I ended up putting babel presets back into package.json.
"babel": {
"presets": [
"#babel/preset-react",
"#babel/preset-env"
]
},
I researched for a while to find a solution to this and apparently webpack has issues bundling symlinked react components? I am not using create-react-app.
So, I tried to bundle the shared_lib before importing it into the project, just to see what would happen. Here's the final webpack config (I tried other configurations as well):
const pkg = require('./package.json');
const path = require('path');
const buildPath = path.join( __dirname, 'dist' );
const clientPath = path.join( __dirname, 'src');
const depsPath = path.join( __dirname, 'node_modules');
const libraryName = pkg.name;
module.exports = [
'cheap-module-source-map'
].map( devtool => ({
bail: true,
mode: 'development',
entry: {
lib : [ 'babel-polyfill', path.join( clientPath, 'index.js' ) ]
},
output: {
path: buildPath,
filename: 'shared_lib.js',
libraryTarget: 'umd',
publicPath: '/dist/',
library: libraryName,
umdNamedDefine: true
},
// to avoid bundling react
externals: {
'react': {
commonjs: 'react',
commonjs2: 'react',
amd: 'React',
root: 'React'
}
},
module: {
rules: [
{
test: /\.jsx?$/,
include: [
clientPath
],
exclude: /node_modules/,
use: [ 'babel-loader' ],
},
]
},
devtool,
optimization: {
splitChunks: {
chunks: 'all',
},
}
}));
And the package.json for the shared_lib
{
"name": "shared_lib",
"version": "1.0.0",
"description": "",
"main": "dist/shared_lib.js",
"scripts": {
"clean": "rm -rf dist/",
"build": "$(npm bin)/webpack --config ./webpack.config.js",
"prepublish": "npm run clean && npm run build"
},
"author": "",
"license": "ISC",
"peerDependencies": {
"react": "^16.8.6"
},
"devDependencies": {
"react": "^16.8.6",
"#babel/core": "^7.9.0",
"#babel/preset-env": "^7.9.0",
"#babel/preset-react": "^7.9.4",
"babel-loader": "^8.1.0",
"babel-polyfill": "^6.26.0",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
},
"babel": {
"presets": [
"#babel/preset-react",
"#babel/preset-env"
]
}
}
The package is bundled without errors:
When I try to import the component in the same way:
import TryTest from 'shared_lib';
The console.log returns undefined.
The path to the library file in my app is fine, because if I erase everything in shared_lib/dist/shared_lib.js and just write export default 1 the console.log(TryTest) in my App.js will return 1.
I tried changing libraryTarget property in shared_lib/webpack.config to libraryTarget: 'commonjs'. The result of console.log(TryTest) becomes {shared_lib: undefined}.
Has anyone ever run into this?
I found what finally worked for me and rendered the symlinked shared_lib to the app.
This answer: https://github.com/webpack/webpack/issues/1643#issuecomment-552767686
Worked well rendering symlinked shared_lib components. I haven't discovered any drawbacks from using this solution, but it's the only one that worked so far.
Hi I am student developer. I facing an error like this
ERROR in ./src/index.js 5:16 Module parse failed: Unexpected token
(5:16) 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 | import App from
'../src/components/App' |
ReactDOM.render(,document.getElementById("app")); i 「wdm」: Failed to compile.
I am starting to learn webpack what it is but I do not have enough information about solving this. Could you help me at this issue to solve ?
package.json Dev Part :
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^8.0.6",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
}
My webconfig :
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.export = {
entry : './src/index.js',
output : {
path:path.join(__dirname,'/dist') ,
filename:'index_bundle.js'
},
module:{
rules : [{
test : /\.js$/,
exclude: /node_modules/,
use : {
loader : 'babel-loader'
}
}]
},
plugins: [
new HtmlWebpackPlugin({
template:'./src/index.html'
})
]
}
index.js
import React from 'react';
import ReactDOM from 'react-dom'
import App from '../src/components/App'
// Error is he
ReactDOM.render(<App />,document.getElementById("app"));
App.js:
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>
<h1>Hello</h1>
</div>
);
}
}
export default App;
There are two mistakes in your webpack configuration, which is causing this issue.
There is a typo error. Change module.export to module.exports (This one drive me crazy man :P)
As #Muhammad mentioned, you need to mention webpack to compile the react. So, I have added '#babel/react' as presets for the babel-loader.
Below is the webpack that is working for me:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry : './src/index.js',
output : {
path:path.join(__dirname,'/dist') ,
filename:'index_bundle.js'
},
module:{
rules : [{
test : /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [
'#babel/react',
]
}
}]
},
plugins: [
new HtmlWebpackPlugin({
template:'./src/index.html'
})
]
}
Hope it helps :)
You need to tell webpack that you are compiling react. You need to update your rule as:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry : './src/index.js',
output : {
path:path.join(__dirname,'/dist') ,
filename:'index_bundle.js'
},
module:{
rules : [{
test: /\.js?$/,
exclude: /node_modules/,
loader: "babel-loader",
query: {
presets: ["react"]
}
}]
},
plugins: [
new HtmlWebpackPlugin({
template:'./src/index.html'
})
]
}
I am trying to import framer library in my project. The project itself compiles just fine if I don't import Hearts.tsx. However it fails just likee below if I import Hearts.tsx. Hearts.tsx imports framer. Unfortunately I am getting an error when I tried to run it with webpack-dev-server.
ERROR in ./node_modules/framer/build/framer.js
Module not found: Error: Can't resolve 'ReactDOM' in '/Users/ikaplan/Code/typeTestFramer/node_modules/framer/build'
# ./node_modules/framer/build/framer.js 1:99-118
# ./src/components/Heart.tsx
# ./src/index.tsx
# multi (webpack)-dev-server/client?http://localhost:9001 ./src/index.tsx
var path = require("path");
module.exports = {
mode: "development",
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: __dirname + "/dist"
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json"]
},
externals: {
react: "react",
"react-dom": "react-dom"
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.tsx?$/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
},
// When importing a module whose path matches one of the following, just
// assume a corresponding global variable exists and use that instead.
// This is important because it allows us to avoid bundling all of our
// dependencies, which allows browsers to cache those libraries between builds.
// webpack-dev-server configuration
// This specifies where javascript bundle is created when
// webpack CLI is run. However, webpack-dev-server is only
// concerned with the 'filename' parameter.
// webpack-dev-server generates the bundle with the 'filename' in
// memory. It never creates an actual file in the 'path' specified
// unlike the webpack CLI.
output: {
path: path.resolve(__dirname, "./dist"),
filename: "bundle.js"
},
devServer: {
// Can be omitted unless you are using 'docker'
// This is where webpack-dev-server serves your bundle
// which is created in memory.
// To use the in-memory bundle,
// your <script> 'src' should point to the bundle
// prefixed with the 'publicPath', e.g.:
// <script src='http://localhost:9001/assets/bundle.js'>
// </script>
publicPath: "/dist/",
// The local filesystem directory where static html files
// should be placed.
// Put your main static html page containing the <script> tag
// here to enjoy 'live-reloading'
// E.g., if 'contentBase' is '../views', you can
// put 'index.html' in '../views/main/index.html', and
// it will be available at the url:
// https://localhost:9001/main/index.html
contentBase: path.resolve(__dirname, "./"),
// 'Live-reloading' happens when you make changes to code
// dependency pointed to by 'entry' parameter explained earlier.
// To make live-reloading happen even when changes are made
// to the static html pages in 'contentBase', add
// 'watchContentBase'
watchContentBase: true,
compress: false,
port: 9001
}
};
This is the detailed error:
ERROR in ./node_modules/framer/build/framer.js
Module not found: Error: Can't resolve 'ReactDOM' in '/Users/ikaplan/Code/typeTestFramer/node_modules/framer/build'
resolve 'ReactDOM' in '/Users/ikaplan/Code/typeTestFramer/node_modules/framer/build'
Parsed request is a module
using description file: /Users/ikaplan/Code/typeTestFramer/node_modules/framer/package.json (relative path: ./build)
Field 'browser' doesn't contain a valid alias configuration
resolve as module
/Users/ikaplan/Code/typeTestFramer/node_modules/framer/build/node_modules doesn't exist or is not a directory
/Users/ikaplan/Code/typeTestFramer/node_modules/framer/node_modules doesn't exist or is not a directory
/Users/ikaplan/Code/typeTestFramer/node_modules/node_modules doesn't exist or is not a directory
/Users/ikaplan/Code/node_modules doesn't exist or is not a directory
/Users/ikaplan/node_modules doesn't exist or is not a directory
/Users/node_modules doesn't exist or is not a directory
/node_modules doesn't exist or is not a directory
looking for modules in /Users/ikaplan/Code/typeTestFramer/node_modules
using description file: /Users/ikaplan/Code/typeTestFramer/package.json (relative path: ./node_modules)
Field 'browser' doesn't contain a valid alias configuration
using description file: /Users/ikaplan/Code/typeTestFramer/package.json (relative path: ./node_modules/ReactDOM)
no extension
Field 'browser' doesn't contain a valid alias configuration
/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM doesn't exist
.ts
Field 'browser' doesn't contain a valid alias configuration
/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM.ts doesn't exist
.tsx
Field 'browser' doesn't contain a valid alias configuration
/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM.tsx doesn't exist
.js
Field 'browser' doesn't contain a valid alias configuration
/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM.js doesn't exist
.json
Field 'browser' doesn't contain a valid alias configuration
/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM.json doesn't exist
as directory
/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM doesn't exist
[/Users/ikaplan/Code/typeTestFramer/node_modules/framer/build/node_modules]
[/Users/ikaplan/Code/typeTestFramer/node_modules/framer/node_modules]
[/Users/ikaplan/Code/typeTestFramer/node_modules/node_modules]
[/Users/ikaplan/Code/node_modules]
[/Users/ikaplan/node_modules]
[/Users/node_modules]
[/node_modules]
[/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM]
[/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM.ts]
[/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM.tsx]
[/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM.js]
[/Users/ikaplan/Code/typeTestFramer/node_modules/ReactDOM.json]
# ./node_modules/framer/build/framer.js 1:99-118
# ./src/components/Heart.tsx
# ./src/index.tsx
What am I missing?
By the way, this is my package.json file:
{
"name": "typetest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"awesome-typescript-loader": "^5.2.0",
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0",
"typescript": "^2.7.1",
"webpack": "^4.17.1",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.4",
"framer": "^0.7.5"
},
"dependencies": {
"#types/react": "^16.3.12",
"#types/react-dom": "^16.0.5",
"#types/draft-js": "^0.10.24",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"source-map-loader": "^0.2.4",
"ReactDOM": "./ReactDOM"
},
"peerDependencies": {
"framer": "^0.7.5",
"react": "^16.3.2",
"react-dom": "^16.3.2"
}
}
It looks like node_modules/framer/build/framer.js is requiring the wrong module name: it should be react-dom, not ReactDOM. I wasn't able to find any documentation indicating how this library is supposed to be used that might suggest why requiring ReactDOM would work. Where was the documentation that pointed you to this library?
Anyway, you should be able to work around the problem by creating a ReactDOM module that just re-exports react-dom. Create a ReactDOM directory with files:
// ReactDOM/index.js
export * from "react-dom";
// ReactDOM/package.json
{"name": "ReactDOM"}
and add "ReactDOM": "./ReactDOM" to your dependencies in package.json.
Maybe the issue it's that your react-dom it's not properly installed.
try
npm install react react-dom --save
and after that your package.json must include the dependencies
Have you checked your package.json now?
An alternative solution is to use the module.resolve option in your Webpack config:
const path = require('path');
module.exports = {
...,
resolve: {
...,
alias: {
...,
React: path.resolve(__dirname, './node_modules/react/'),
ReactDOM: path.resolve(__dirname, './node_modules/react-dom/')
}
}
}
I had a similar problem using a different library, and this solved it for me!
is better update react and react-dom to latest version ,
npm install react#latest react-dom#latest ,
i changed packaje.json ("react": "^18.2.0","react-dom": "^18.2.0") then used nmp i
I hope , have helped
Currently I'm struggling to get HMR working in my Webpack 2 setup. I'll explain my entire setup so I hope this is enough for someone to understand what's happening.
The structure of my project:
config
dev.js
prod.js
dist
css
js
index.html
node_modules
src
components
// some JavaScript components
shared
stylesheets
index.js
.babelrc
package.json
webpack.config.js
This are the contents of my webpack.config.js file, placed in the root of my project:
function buildConfig(env) {
return require('./config/' + env + '.js')(env)
}
module.exports = buildConfig;
So in this file I've the option to pass different environments to the buildConfig function. I use this options to use different config files for development and production. This are the contents in my package.json file:
{
"main": "index.js",
"scripts": {
"build:dev": "node_modules/.bin/webpack-dev-server --env=dev",
"build:prod": "node_modules/.bin/webpack -p --env=prod"
},
},
"devDependencies": {
"autoprefixer-loader": "^3.2.0",
"babel-cli": "^6.18.0",
"babel-core": "^6.24.1",
"babel-loader": "^6.2.5",
"babel-preset-latest": "^6.16.0",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-0": "^6.16.0",
"css-loader": "^0.25.0",
"extract-text-webpack-plugin": "^2.1.0",
"json-loader": "^0.5.4",
"node-sass": "^3.13.1",
"postcss-loader": "^1.3.3",
"postcss-scss": "^0.4.1",
"sass-loader": "^4.1.1",
"style-loader": "^0.13.1",
"webpack": "^2.4.1",
"webpack-dev-server": "^2.4.2"
},
"dependencies": {
"babel-plugin-react-css-modules": "^2.6.0",
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-hot-loader": "^3.0.0-beta.6",
"react-icons": "^2.2.1"
}
}
I've of course more fields in my package.json but I won't shown them here since they're irrelevant.
So during development I run the npm run build:dev command in my terminal. This will use the file dev.js from the config folder. This are the contents of the dev.js file:
const webpack = require('webpack');
const { resolve } = require('path');
const context = resolve(__dirname, './../src');
module.exports = function(env) {
return {
context,
entry: {
app: [
'react-hot-loader/patch',
// activate HMR for React
'webpack-dev-server/client?http://localhost:3000',
// bundle the client for webpack-dev-server
// and connect to the provided endpoint
'webpack/hot/only-dev-server',
// bundle the client for hot reloading
// only- means to only hot reload for successful updates
'./index.js'
// the entry point of our app
]
},
output: {
path: resolve(__dirname, './../dist'), // `dist` is the destination
filename: '[name].js',
publicPath: '/js'
},
devServer: {
hot: true, // enable HMR on the server
inline: true,
contentBase: resolve(__dirname, './../dist'), // `__dirname` is root of the project
publicPath: '/js',
port: 3000
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.js$/, // Check for all js files
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
query: {
presets: ['latest', 'react'],
plugins: [
[
"react-css-modules",
{
context: __dirname + '/../src', // `__dirname` is root of project and `src` is source
"generateScopedName": "[name]__[local]___[hash:base64]",
"filetypes": {
".scss": "postcss-scss"
}
}
]
]
}
}]
},
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true,
modules: true,
importLoaders: 2,
localIdentName: '[name]__[local]___[hash:base64]'
}
},
'sass-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => {
return [
require('autoprefixer')
];
}
}
}
]
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
// enable HMR globally
new webpack.NamedModulesPlugin()
// prints more readable module names in the browser console on HMR updates
]
}
};
And last but not least, my HMR setup. I've this setup in my index.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import TodoApp from './components/TodoApp';
import './stylesheets/Stylesheets.scss';
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.querySelector('#main')
);
};
render(TodoApp);
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/TodoApp', () => {
render(TodoApp)
});
}
So, when I run my npm start build:dev in my browser and go to http://localhost:3000 I see my site working as expected. This is the output in the console:
dev-server.js:49 [HMR] Waiting for update signal from WDS...
only-dev-server.js:66 [HMR] Waiting for update signal from WDS...
TodoApp.js:102 test
client?344c:41 [WDS] Hot Module Replacement enabled.
The test text comes from the render function in my TodoApp component. This function looks like this:
render() {
console.log('test');
return(
<div styleName="TodoApp">
<TodoForm addTodo={this.addTodo} />
<TodoList todos={this.state.todos} deleteTodo={this.deleteTodo} toggleDone={this.toggleDone} updateTodo={this.updateTodo} />
</div>
);
}
So, now the important stuff. I update the return of this render function, which should trigger the HMR to kick in. I change the render function to this.
render() {
console.log('test');
return(
<div styleName="TodoApp">
<p>Hi Stackoverflow</p>
<TodoForm addTodo={this.addTodo} />
<TodoList todos={this.state.todos} deleteTodo={this.deleteTodo} toggleDone={this.toggleDone} updateTodo={this.updateTodo} />
</div>
);
}
This is the output I get in the console:
client?344c:41 [WDS] App updated. Recompiling...
client?344c:41 [WDS] App hot update...
dev-server.js:45 [HMR] Checking for updates on the server...
TodoApp.js:102 test
log-apply-result.js:20 [HMR] Updated modules:
log-apply-result.js:22 [HMR] - ./components/TodoApp.js
dev-server.js:27 [HMR] App is up to date.
You would say this is good. But my site doesn't update ANYTHING.
Then I change the the HMR code in my index.js to this:
// Hot Module Replacement API
if (module.hot) {
module.hot.accept();
}
And it works. I just don't get it. Why doesn't it work if this is my HMR code:
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/TodoApp', () => {
render(TodoApp)
});
}
BTW this setup is based on the setup from https://webpack.js.org/guides/hmr-react/
I hope that anyone can help me. If someone needs more information don't hesitate to ask. Thanks in advance!
UPDATE
Forgot to post my .babelrc file. This is it:
{
"presets": [
["es2015", {"modules": false}],
// webpack understands the native import syntax, and uses it for tree shaking
"react"
// Transpile React components to JavaScript
],
"plugins": [
"react-hot-loader/babel"
// EnablesReact code to work with HMR.
]
}
The imports are static and after an update has been identified in module.hot.accept you render the exact same component again, as the TodoApp still holds the old version of your module and HMR realises that and doesn't refresh or change anything in your app.
You want to use Dynamic import: import(). To make it work with babel you need to add babel-plugin-syntax-dynamic-import, otherwise it will report a syntax error as it didn't expect import to be used as a function. The react-hot-loader/babel is not needed if you use react-hot-loader/patch in your webpack config, so your plugins in your .babelrc become:
"plugins": [
"syntax-dynamic-import"
]
In your render() function you can now import the TodoApp and render it.
const render = () => {
import('./components/TodoApp').then(({ default: Component }) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.querySelector('#main')
);
});
};
render();
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/TodoApp', render);
}
import() is a promise that will resolve with the module, and you want to use the default export.
Even though the above is true, the webpack documentation doesn't require you to use dynamic imports, because webpack handles ES modules out of the box, also described in react-hot-loader docs - Webpack 2, and because webpack is also handling the HMR, it will know what to do in that case. For this to work, you must not transform the modules to commonjs. You did this with ["es2015", {"modules": false}], but you also have the latest preset configured in your webpack config, which also transforms the modules. To avoid confusion, you should have all babel configurations in .babelrc instead of splitting some to the loader options.
Remove the presets in the babel-loader entirely from your webpack config and it will work as you already have the necessary presets in your .babelrc. babel-preset-latest is deprecated and if you want to use these features you should start using babel-preset-env which also replaces es2015. So your presets in .babelrc would be:
"presets": [
["env", {"modules": false}],
"react"
],
Check this issue on GitHub or just use this in your index.js:
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import App from './components/App'
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component/>
</AppContainer>,
document.getElementById('react-root')
)
}
render(App)
if(module.hot) {
module.hot.accept();
}
After migrating to Webpack 2, using gulp to run webpack with webpack-stream seems to cause babel or webpack to throw an error (can't tell where error originates from). Running webpack with the config and structure below builds successfully but piping it through gulp and webpack-stream causes this error:
Message:
./app/app.jsx
Module parse failed: /Users/schne482/Code/tralgo/app/app.jsx Unexpected token (11:1)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token (11:1)
at Parser.pp$4.raise (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:2221:15)
at Parser.pp.unexpected (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:603:10)
at Parser.pp$3.parseExprAtom (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:1822:12)
at Parser.pp$3.parseExprSubscripts (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:1715:21)
at Parser.pp$3.parseMaybeUnary (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:1692:19)
at Parser.pp$3.parseExprOps (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:1637:21)
at Parser.pp$3.parseMaybeConditional (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:1620:21)
at Parser.pp$3.parseMaybeAssign (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:1597:21)
at Parser.pp$3.parseParenAndDistinguishExpression (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:1861:32)
at Parser.pp$3.parseExprAtom (/Users/schne482/Code/tralgo/node_modules/webpack-stream/node_modules/acorn/dist/acorn.js:1796:19)
Details:
domain: [object Object]
domainThrown: true
What I have done:
Changed the structure of webpack.config.js to obey Webpack 2.
Moved babel config to separate .babelrc. No visible effects.
Ensured .babelrc has correct structure.
Ensured Webpack points to correct entry file (./app/app.jsx) and entry file is processed by loaders.
Ran babel (babel ./app/app.jsx) without webpack using same .babelrc and dependencies. Output was correct, no errors.
Ran webpack without gulp, output was correct.
Updated relevant packages (babel-core, babel-loader, babel presets, webpack-stream, gulp, etc..).
Checked for any simple syntax errors.
Here are the relevant files:
gulpfile.js:
const gulp = require('gulp');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
const webpack_config = require('./webpack.config');
function webpack_build_dev() {
webpack_config.devtool = 'eval-source-map';
return gulp.src('app/app.jsx')
.pipe(webpackStream(webpack_config), webpack)
.pipe(gulp.dest('./'));
}
gulp.task('webpack:build:dev', gulp.series('clean', webpack_build_dev));
./app/app.jsx:
import React from 'react';
import { render } from 'react-dom';
const app = (
<h1>Hello</h1>
);
render(
app,
document.getElementById('app')
);
./webpack.config.js:
const webpack = require('webpack');
const path = require('path');
module.exports = {
context: path.resolve(__dirname, './app'),
entry: './app.jsx',
output: {
path: path.resolve(__dirname, './public'),
filename: 'bundle.js',
},
resolve: {
modules: [
path.resolve(__dirname, './app'),
"node_modules",
],
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
use: 'babel-loader',
},
],
},
};
./.babelrc:
{
"presets": [
"es2015",
"react"
]
}
./package.json (relevant devDependencies):
{
"devDependencies": {
"babel-core": "^6.22.1",
"babel-loader": "^6.3.2",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.22.0",
"webpack": "^2.2.1",
}
}
Not at a PC at the moment so can't test this, but can you try:
Change import to:
import ReactDOM from 'react-dom'
Then change render to:
ReactDOM.render (
...
)
Have you tried to add
"plugins": ["transform-object-rest-spread", "babel-plugin-transform-react-jsx"]
to your .babelrc file?