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>
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
The order of the scripts that are loaded in index.ejs is incorrect. Now it is:
<link rel="preload" as="script" href="/views/index.js">
<link rel="preload" as="script" href="/views/vendor.js">
This means your index.js
will be loaded before vendor.js
causing your app to not appear at all. First all your app's dependencies should be loaded (vendor.js
) and only then index.js
since you need the dependencies to be present while executing your custom code. So it should be:
<link rel="preload" as="script" href="/views/vendor.js">
<link rel="preload" as="script" href="/views/index.js">
Edit:
As we figured out eventually, the issue was not in the order of the scripts, but due to the fact that the scripts weren't actually loaded in the html
. For that they need to be added as chunks in HtmlWebpackPlugin
and injected into index.html
:
new HtmlWebpackPlugin({
title: "Deals",
filename: __dirname + "/views/index.ejs",
template: __dirname + "/views/template.ejs",
inject: 'body',
chunks: ['vendor', 'index']
})
Moreover, the configuration for the chunk meta
was removed completely. All the rest of the configuration (including PreloadWebpackPlugin
) was fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With