It's been a day I'm trying to solve this annoying but, I'm sure, simple issue. I am trying to divide my bundle.js into chunks to optimize website loading time.
Here is my webpack.config file :
module.exports = {
devServer: {
historyApiFallback: true
},
entry: {
index: ["./src/index.js"],
vendor: [
"react",
"react-dom",
"react-redux",
"react-router",
"react-router-dom",
"redux"
]
},
output: {
path: __dirname + '/public/views',
filename: "[name].js",
publicPath: "/views/"
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: [/node_modules/, /pdfmake.js$/]
},
{
test: /\.json$/,
loader: "json-loader"
}
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "vendor.js",
minChunks: Infinity
}),
new webpack.optimize.CommonsChunkPlugin({
name: "meta",
chunks: ["vendor"],
filename: "meta.js"
}),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
title: "Deals",
filename: __dirname + "/views/index.ejs",
template: __dirname + "/views/template.ejs",
inject: false
}),
new PreloadWebpackPlugin({
rel: "preload",
as: "script",
include: "all"
}),
new webpack.optimize.OccurrenceOrderPlugin(),
]
};
Here is my my simplified index.ejs, file created by running webpack code, result from template.ejs :
<!DOCTYPE html>
<html lang="en">
<head>
<link href="/pace.css" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=yes">
<meta charset="utf-8">
<link rel="stylesheet" href="/style.css">
<link rel="canonical" href="http://verygoodprof.fr/" />
<link rel="preload" as="script" href="/views/index.js">
<link rel="preload" as="script" href="/views/vendor.js">
<link rel="preload" as="script" href="/views/meta.js">
</head>
<body>
<noscript>
<a href="http://enable-javascript.com/">Javascript must me enabled to use this site.</a>
</noscript>
<div class="text-center root" id="root">
</div>
</body>
</html>
Here, I see I've got my preloaded chunks, dynamically written, as wanted, and those chunks are in the correct folder, created after running the webpack code.
And here is my index.js file (React), stated to be the index entry in webpack.config file
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<AppInit>
<BrowserRouter>
<div style={{ height: "100%" }}>
<ProfRegisteringModal />
<Switch>
{/* <Route path="/inscription/:user" component={Registering} />
<Route path="/inscription" component={Registering} />
<Route path="/connexion" component={SigningIn} />
<Route path="/equipe" component={TeamPres} />
<Route path="/" component={AppContainer} /> */}
<Route
path="/inscription/:user"
getComponent={(location, callback) => {
require.ensure(
[],
function(require) {
callback(
null,
require("./components/registering/registering_landing_page.js")
);
},
"registerChunk"
);
}}
/>
<Route
path="/inscription"
getComponent={(location, callback) => {
require.ensure(
[],
function(require) {
callback(
null,
require("./components/registering/registering_landing_page.js")
);
},
"registerChunk"
);
}}
/>
<Route
path="/connexion"
getComponent={(location, callback) => {
require.ensure(
[],
function(require) {
callback(
null,
require("./containers/registering/signing_in.js")
);
},
"signinChunk"
);
}}
/>
<Route
path="/equipe"
getComponent={(location, callback) => {
require.ensure(
[],
function(require) {
callback(null, require("./components/team_pres.js"));
},
"teampresChunk"
);
}}
/>
<Route
path="/"
getComponent={(location, callback) => {
require.ensure(
[],
function(require) {
callback(null, require("./containers/app_container.js"));
},
"appContainerChunk"
);
}}
/>
</Switch>
</div>
</BrowserRouter>
</AppInit>
</Provider>,
document.querySelector(".root")
);
The first thing I notice is that the chunks that are supposed to be build are correctly built for vendor and meta but not for my inner react components. But this is not the major issue, the fact is, when running the server locally, I can't see my react app at all. The index.ejs file is correctly loaded though when I check in the console.
Everything was working perfectly when using a simple bundle.js file with everything inside (no chunks). With an index.ejs pointing to it as
<script src="/views/bundle.js"></script>
Thank you very much for your help !
EDIT
This webpack.config file made it work (credits to @margaretkru):
module.exports = {
devServer: {
historyApiFallback: true
},
entry: {
app:"./src/index.js",
vendor: [
"axios",
"jquery",
"react",
"react-dom",
"react-redux",
"react-router",
"react-router-dom",
"redux"
]
},
output: {
path: __dirname + '/public/views',
filename: "[name].js",
publicPath: "/views/"
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: [/node_modules/, /pdfmake.js$/]
},
{
test: /\.json$/,
loader: "json-loader"
}
]
},
plugins: [
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
filename: __dirname + "/views/index.ejs",
template: __dirname + "/views/template.ejs",
inject: 'body',
chunks: ['vendor', 'app'],
chunksSortMode: 'manual'
}),
new PreloadWebpackPlugin({
rel: "preload",
include: ["vendor", "app"]
}),
new webpack.optimize.OccurrenceOrderPlugin(),
]
};new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: Infinity
}),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
filename: __dirname + "/views/index.ejs",
template: __dirname + "/views/template.ejs",
inject: 'body',
chunks: ['vendor', 'app'],
chunksSortMode: 'manual'
}),
new PreloadWebpackPlugin({
rel: "preload",
include: ["vendor", "app"]
}),
new webpack.optimize.OccurrenceOrderPlugin(),
]
};
The real issue was not the loaded scripts ordering but more that I was not actually loading the scripts after "pre-loading" them : The "inject" line of the HTMLWebpackPlugin helped since it injected those two lines :
<script src="/views/vendor.js"/>
<script src="/views/app.js"/>
in my index.ejs body
index.ejs
is incorrect, first should be loadedvendor.js
andmeta.js
and only THENindex.js
. But I don't understand why the order is wrong. – Rafa