Multiple modules for multiple entry points in webpack config for reactjs app - reactjs

In case of multiple entry points, this is the example I got:
module.exports = {
entry: {
user1: path.join(__dirname, './client/app1.js'),
user2: path.join(__dirname, './client/app2.js'),
user3: path.join(__dirname, './client/app3.js')
},
output: {
path: path.join(__dirname, './static/bundle/'),
filename: '[name].js'
},
...
}
But, I am confused about the term entry. Does it mean the entry url? What if user visits to root and then visits another page?
For example, suppose I have one site example.com and two other pages example.com/register and example.com/contact. Now I want to get common files for example.com and load only register module code in example.com/register and contact module code in example.com/contact. The entry point is same, example.com. Will above solution work in this scenario?

But, I am confused about the term entry. Does it mean the entry url?
No. It is the entry for webpack to start bundling. If you have multiple entries in your webpack config, then there will be multiple output bundles. This is why you output uses a [name].js in the filename.
It is up to you to make sure the correct bundle(s) are available to any particular page that is loaded.
Answering question in comment:
If I understand what you are trying to do, I believe you can use CommonsChunkPlugin to construct a common bundle and an entry for each page.
So your webpack config might look something like
module.exports = {
entry: {
index: path.join(__dirname, './src/index.js'),
register: path.join(__dirname, './src/register.js'),
contact: path.join(__dirname, './src/contact.js')
},
output: {
path: path.join(__dirname, './static/bundle/'),
filename: '[name].js'
},
plugins: [
new CommonsChunkPlugin("commons.js")
]
...
}
Then your index page would be something like
<html>
<head></head>
<body>
...
<script src="static/bundle/commons.js"></script>
<script src="static/bundle/index.js"></script>
</body>
</html>
And the register page would be something like
<html>
<head></head>
<body>
...
<script src="static/bundle/commons.js"></script>
<script src="static/bundle/register.js"></script>
</body>
</html>
And the contact page would be something like
<html>
<head></head>
<body>
...
<script src="static/bundle/commons.js"></script>
<script src="static/bundle/contact.js"></script>
</body>
</html>

Related

Output multiple React apps from one Webpack config

I'm working on a web app that has a companion WordPress site. Let's assume domains like:
app.site.com
blog.site.com
What I'd like to do is have my webpack 4 configuration output the bundle.js but also generate something like header.js that includes a single <Header /> component (not the complete app).
Then I'd add a script tag to blog.site.com like so:
<script src="https://app.site.com/build/header.js" />`
and expect it to mount the app's <Header /> in the blog's #dom-element
How can this be achieved?
Create the another entry point for header component. Quoting from webpack docs:
module.exports = {
entry: {
bundle: './src/app.js',
header: './src/header.js'
},
output: {
filename: '[name].js',
path: __dirname + '/build'
}
};
This will create bundle.js from your inital entry point. And also header.js from the Header component.

Angular "Module is not available" when switching to webpack

My project is trying to switch from pure Javascript scripts to webpack. We have an html file, game.html, that has the following content:
<html>
...
<script src="bundle.js"></script>
...
<div ng-app="visualizerApp" ng-controller="VisualizerController as ctrl">
...
</div>
...
</html>
before switching to webpack, we just had a long list of scripts.
The angular module is created in a file app.js
import angular from 'angular';
class VisualizerController {...}
VisualizerController.$inject = ['$scope', '$rootScope'];
angular.module('visualizerApp', []).controller('VisualizerController', VisualizerController);
before switching, the file was identical except for the import statement.
When opening the html file, we get an error in the console:
[$injector:modulerr] Failed to instantiate module visualizerApp due to:
Error: [$injector:nomod] Module 'visualizerApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Why does this happen and how can I solve it?
edit: my webpack.config.js
const path = require('path');
const mapType = require('./root/visualizer/js/map/PluginManager').mapType;
module.exports = {
entry: './plugins/root/visualizer/js/main.js',
output: {
filename: '../game_logs/bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /tests/,
use: {
loader: 'babel-loader',
options: {
presets: ['babel-preset-env']
}
}
}
]
},
resolve: {
alias: {
mapPlugin: path.resolve(__dirname, 'map/' + mapType),
}
}
};
library versions:
├── angular#1.6.8
├── babel-cli#6.26.0
├── babel-loader#7.1.2
└── webpack#3.10.0
It looks like angular is loaded but not your other scripts. I would start by looking at bundle.js to make sure that what you expect to be there is actually there.
You haven't shared your webpack configuration so it's hard to say definitively what's happening. Webpack changes the dynamic of how your scripts are loaded.
I would also suggest using angular.bootstrap in order to bootstrap your application instead of ng-app.
Try the following:
<html>
...
<script src="bundle.js"></script>
...
<div id="visualizerApp" ng-controller="VisualizerController as ctrl">
...
</div>
...
</html>
And in your Javascript:
import angular from 'angular';
class VisualizerController {...}
VisualizerController.$inject = ['$scope', '$rootScope'];
angular
.module('visualizerApp', [])
.controller('VisualizerController', VisualizerController);
angular.element(document).ready(function() {
let container = document.querySelector('#visualizerApp');
angular.bootstrap(container, ['visualizerApp'])
});
angular.bootstrap allows you to manage when your application is bootstrapped. Not just when angular loads.
Here's a working fiddle which uses angularjs 1.5.6 and ES5.

HelloWorld example returns a syntax error on React

I tried to check all the libraries/packages that I needed to run a simple example of HelloWorld on React.js without success.
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
The error is the following:
/Users/Silvio/WebstormProjects/untitled/main.js:5
<h1>Hello, world!</h1>,
^
SyntaxError: Unexpected token <
I have installed babel and ReactDOM.
In your .babelrc file you need to specify the following
{
"presets": ["react", "stage-0", "es2015"]
}
Also you need to install the above presets like
npm install -S babel-preset-react babel-preset-stage-0 babel-preset-es2015
Along with that you webpack.config.js must look something like below to enable babel for .js or .jsx file extensions
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './main.js',
output: { path: __dirname, filename: 'bundle.js' },
module: {
loaders: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
}
]
},
};
You can refer here and here for more details
The code itself is correct, but you probably aren't running it properly as it is meant to be run in the browser, not in Node.js. If require is used to import dependencies, main.js must first be processed by a bundler like webpack before it is ready for use.
The following snippet is essentially the same code that you have posted but the dependencies (React and ReactDOM) are imported via script tags.
ReactDOM.render(<h1>Hello, world</h1>, document.getElementById("example"))
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello, world</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.js"></script>
</head>
<body>
<div id="example"></div>
</body>
</html>
Here Babel, which transpiles JSX (<h1>Hello, world</h1>) is provided by the snippet editor. This minimal example imports Babel as a dependency and transpiles the JSX portion at run time.
You need to run this through babel first - with react and stage-0 presets enabled.
We do this for our sample code here:
https://github.com/flexicious/react-redux-datagrid

How React JS index.js file contacting index.html for id references? [duplicate]

This question already has answers here:
Where's the connection between index.html and index.js in a Create-React-App application?
(2 answers)
Closed 3 years ago.
I recently get started with react.
My index.html contains
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
and index.js contains
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
ReactDOM.render(
<App />,
document.getElementById('root')
);
My doubt is I didn't mention index.js in any script tag in index.html. But how it is referencing the root div element in index.html? I was wondering as it is working fine. Please explain me.
I had run these commands to create the app
npm install -g create-react-app
create-react-app hello-world
cd hello-world
npm start
Create-React-App has a very interesting setup.
I started digging in the package.json npm script start
"start": "react-scripts start"
That takes me to their binary react-scripts under node_modules/.bin
I'll post the relevant stuff here.
switch (script) {
case 'build':
case 'eject':
case 'start':
case 'test': {
const result = spawn.sync(
'node',
[require.resolve('../scripts/' + script)].concat(args),
{ stdio: 'inherit' }
);
So this tells me that they are looking for script inside ../scripts/ folder.
So I go to the react-scripts npm module(node_modules/react-scripts) and open up the node_modules/react-scripts/scripts/start.js file since I was doing npm start.
Now here is where I found the webpack config I was looking for.
They were specifically referring to node_modules/react-scripts/config/webpack.config.dev.js. I'll post the relevant stuff here.
entry: [
// Finally, this is your app's code:
paths.appIndexJs,
],
plugins: [
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
So file referred by paths.appIndexJs is the entry file in the webpack config.
And they are using HtmlWebpackPlugin to load the html at the path paths.appHtml.
Final piece of the puzzle is linking this back to the files you posted.
Posting relevant stuff from paths.js
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
module.exports = {
...
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveApp('src/index.js'),
...
}
So inside your application directory,
appHtml is file public/index.html
appIndexJs is file src/index.js
Your two files in question.
Wow! That was quite a journey..:P
Update 1 - As of react-scripts#3.x
The react-scripts binary under node_modules/.bin has changed the logic as below. Essentially doing the same thing.
if (['build', 'eject', 'start', 'test'].includes(script)) {
const result = spawn.sync(
'node',
nodeArgs
.concat(require.resolve('../scripts/' + script))
.concat(args.slice(scriptIndex + 1)),
{ stdio: 'inherit' }
);
The webpack configs for dev & prod has been combined into one.
const configFactory = require('../config/webpack.config');
The HTMLWebpackPlugin config looks like this - This is since they have to conditionally add production config on top of this
plugins: [
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
},
The paths file code has some updates
module.exports = {
...
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
...
};

How can I render the react app with redux using the ReactJS.NET?

I have created the Single page application where I have used the React, Redux and React-Router.
I want to render this SPA using ReactJS.NET for improve perfomance of loading the application.
The SPA is compiled as one Bundle.js using Webpack.
I have an ASP.NET MVC application where I can paste this bundle which will be rendered through the ReactJS.NET. Everything in this SPA will be worked in one ASP.NET view but with the React-router.
How can I do that? I can't find any project where is solved this combination with redux.
Thank you for the example or help.
I know this is an old question but if you're still having issues incorporating your React app into React.NET you should try the following template and have a look at how this fellow has done it.
He uses webpack to first build and compile a server specific set of code then pulls the compiled js into React.NET
app.UseReact(config =>
{
config
.SetLoadBabel(false)
.AddScriptWithoutTransform("~/js/react.server.bundle.js");
});
The webpack config looks like this.
var path = require('path');
var webpack = require('webpack');
var WebpackNotifierPlugin = require('webpack-notifier');
module.exports = {
entry: {
server: './React/server.jsx',
client: './React/client.jsx',
clientWithRender: './React/clientWithRender.jsx',
},
output: { path: __dirname + '/wwwroot/js/', filename: 'react.[name].bundle.js' },
module: {
loaders: [
{
test: /.jsx?$/,
loader: "babel-loader",
exclude: /node_modules/,
query: {
presets: ['es2015', 'react'],
plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
}
}
]
},
plugins: [
new WebpackNotifierPlugin()
]
};
And heres the index
#{
Layout = null;
}
<html>
<head>
<title>Hello React</title>
</head>
<body>
<div id="app">
#{
if (Environment.GetEnvironmentVariables()["ASPNETCORE_ENVIRONMENT"].ToString() != "Development")
{
#Html.React("ReactComponents.App", new { val1 = "Top text" });
}
}
</div>
#{
if (Environment.GetEnvironmentVariables()["ASPNETCORE_ENVIRONMENT"].ToString() != "Development")
{
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.min.js"></script>
<script src="#Url.Content("~/js/react.client.bundle.js")"></script>
#Html.ReactInitJavaScript()
}
else
{
<script src="#Url.Content("~/js/react.clientWithRender.bundle.js")"></script>
}
}
</body>
</html>
Why use ReactJS.NET? There is nothing special about an MVC.NET stack which requires a separate project to get React up and running in it. I would use a combination of Babel, Webpack, React, React-Dom and React-Router instead. MVC.NET should just deliver the bundle everything else should be react and it's dependencies.
The problem with the default tutorial of React.NET is that it does not consider the fact you are using webpack to bundle your dependencies and instead has examples of adding them manually. This is not really the preferred way of writing React and makes a complicated process even more complicated by trying to hide away the initial complexity of setting up your React project.
Suggestion:
Webpack will bundle your react-router, react and react-dom amongst other stuff. You need MVC to be setup in a way that every url request is handled by the same controller action that way React-Router can handle the url changes. This answer explains how to do this. ASP.NET MVC - Catch All Route And Default Route
Without doing this, MVC will try to handle all url route changes instead of React-Router doing it's thing.

Resources