I'm getting a MissingEntryError when I use javascript_packs_with_chunks_tag but not with javascript_pack_tag. Here's the aforementioned error:
Rescued toplevel: Webpacker can't find react-manager in /my_app/public/packs/manifest.json.
...
Your manifest contains:
{
"react-manager.css": "/packs/react-manager-66702cf30ae4ffc6025f.css",
"react-manager.js": "/packs/react-manager-66702cf30ae4ffc6025f.js",
"vendors~react-manager.js": "/packs/vendors~react-manager-eb2e5fd06be7538f6120.js",
...
}
Clearly _react_manager_ is present in the manifest and in the packs directory, so I'm not sure what the issue is. Note: I'm using _Webpacker 4.0.0.rc.7_ with _Webpack 4.29.5_. and react_on_rails' recommended project structure.
Here are my source files (edited for readability):
config/webpacker.yml
default: &default
cache_path: tmp/cache/webpacker
compile: false
public_output_path: packs
source_path: client
development:
<<: *default
test:
<<: *default
public_output_path: packs-test
staging: &staging
<<: *default
cache_manifest: true
production:
<<: *staging
webpack.config.js
const ManifestPlugin = require('webpack-manifest-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { resolve } = require('path');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const webpackConfigLoader = require('react-on-rails/webpackConfigLoader');
const configPath = resolve('..', 'config');
const { output } = webpackConfigLoader(configPath);
module.exports = (env, args) => ({
context: resolve(__dirname, 'app'),
devtool: args.mode === 'development' ? 'source-map' : false,
entry: {
'react-manager': [
'./bundles/manager/startup/managerRegistration',
],
},
output: {
filename: '[name]-[chunkhash].js',
path: output.path,
publicPath: output.publicPath,
},
resolve: {
extensions: ['.js', '.jsx', '.scss'],
modules: [
'client/app',
'client/node_modules',
],
},
module: {
rules: [
{
exclude: resolve(__dirname, 'node_modules'),
test: /\.jsx?$/,
use: 'babel-loader',
},
{
exclude: resolve(__dirname, 'node_modules'),
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
localIdentName: '[local]___[hash:base64:5]',
modules: true,
sourceMap: args.mode === 'development',
},
},
'sass-loader',
],
},
],
},
optimization: {
runtimeChunk: {
name: 'manifest',
},
splitChunks: {
chunks: 'all',
},
minimizer: [
new UglifyJsPlugin({
sourceMap: args.mode === 'development',
}),
new OptimizeCSSAssetsPlugin({}),
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]-[chunkhash].css',
}),
new ManifestPlugin({
publicPath: output.publicPath,
}),
],
});
index.html.erb
<!DOCTYPE html>
<html lang="en">
<head>
<title>My App</title>
<%= stylesheet_packs_with_chunks_tag "react-manager" %>
</head>
<body>
<%= javascript_packs_with_chunks_tag 'react-manager' %>
</body>
</html>
Any help is much appreciated, thanks!
It looks like Webpacker is expecting this JSON schema for _manifest.json_:
{
"entrypoints": {
"js": {
"react-manager": "/packs/react-manager-66702cf30ae4ffc6025f.js"
}
}
}
I'm not positive, but is that the CommonsChunk JSON schema?
Wepacker says it supports Webpack v4; however, the Webpack v4 documentation recommends using SplitChunksPlugin in combination with the ManifestPlugin (see here). The issue is, the ManifestPlugin doesn't output the manifest in the required schema, it uses the standard schema that javascript_pack_tag expects.
There's another manifest plugin, https://github.com/webdeveric/webpack-assets-manifest, it supports an option entrypoints (https://github.com/webdeveric/webpack-assets-manifest#entrypoints), which compiles a manifest with the entrypoints schema.
Can confirm, I have exactly the same issue 馃憤
Did you find any workaround?
@robbymarston @h0jeZvgoxFepBQ2C Can you post the entire error log with the entire manifest.json file?
Looks like this is working for me:
in webpack environment.js
const WebpackAssetsManifest = require('webpack-assets-manifest');
environment.plugins.insert(
'Manifest',
new WebpackAssetsManifest({
entrypoints: true,
writeToDisk: true,
publicPath: true,
done: function(manifest, stats) {
console.log(`The manifest has been written to ${manifest.getOutputPath()}`);
console.log(`${manifest}`);
}
})
)
and then use
# NOT WORKING WITH JS ENDING!
=javascript_packs_with_chunks_tag "quick_add/index.js"
# WORKS JS ENDING!!!!
=javascript_packs_with_chunks_tag "quick_add/index"
Strange thing is now, that it doesnt work anymore with javascript_include_tag :( It outputs a include tag, but somehow the JS is not loaded.. Dunno why.
Ok this f... still not working, since my chunks are loaded twice :( When I only use javascript_pack_tag it renders the javascript include tag, but the JS is not executed somehow, not even a console.log("Hi") at the top of my component1 file.
Can somone post an example on how to do following basic stuff?
# application_layout
=javascript_packs_with_chunks_tag "application"
# includes polyfill, moment and some other basic libraries
# subsite 1
=javascript_pack_tag "react_component1"
# imports react,axios and react_component1
# subsite 1
=javascript_pack_tag "react_component2"
# imports react,axios and react_component2
And with splitchunks each npm module should be in its own file (https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758?gi=3cd6ba7651c0)
React, Axios,.. is imported in each react component, but should (logically) only loaded once?
I just can't make it work :( This should be basic stuff and not take 30+ hours to finish :( I miss the old times where I could just use sprockets and just require these things easily.
@h0jeZvgoxFepBQ2C, let me repurpose my comment from here https://github.com/rails/webpacker/issues/1835#issuecomment-456569708:
Splitting your app into multiple packs, just to load them on the same page is the waste of performance and compile time. Webpack is assuming that those different entrypoints are on exclusive pages (hence the duplication).
Example: <%= javascript_packs_with_chunks_tag 'application', 'react_component1', 'react_component2' %>
<%
# Some erb that loads in <head>.
# We need a way to get rails/erb data into webpack-land,
# the best way is to just have a "flag" for each chunk you might want to load.
%>
<script>
window.lazyChunks = {
react_component1: <%= @lazy_chunks[: react_component1].present? %>,
react_component2: <%= @lazy_chunks[: react_component2].present? %>,
};
</script>
<%= javascript_packs_with_chunks_tag 'application' %>
``erb
<% # Some partial that contains your react_component1 component %>
<% # Setting this here will makewindow.lazyChunks.react_component1` true in webpack-land %>
<%= @lazy_chunks[:react_component1] = true %>
```js
// application.js
if(window.lazyChunks.react_component1) // resolves to true from the other file
import(/* webpackMode: "lazy" */ // can be 'lazy', 'lazy-once', 'eager', or 'weak'
/* webpackChunkName: "react_component1" */ // Adding this comment will cause our separate chunk to be named [my-chunk-name].js instead of [id].js.
'./../file/path/to/react_component1');
if(window.lazyChunks.react_component2)
import(/* webpackMode: "lazy" */
/* webpackChunkName: "react_component2" */
'./../file/path/to/react_component2');
Docs for using ES6 dynamic import().
Docs for using ES6 dynamic import for webpack.
Edit: This is not new, it has been a standard feature since 2017. IMHO, it is not used nearly enough.
Any sub-files that you need to load will be available to this single entrypoint. Without this, you are fighting and negating any tree-shaking. Better yet, but using dynamic import, webpack can automatically generate vendor chunks (like React) that are shared between your lazy chunks!
These are the same methods that your linked guide uses. You can further customize this in webpackER via splitChunks, here is the doc: https://github.com/rails/webpacker/blob/master/docs/webpack.md#add-splitchunks-webpack-v4
I just can't make it work :( This should be basic stuff and not take 30+ hours to finish :( I miss the old times where I could just use sprockets and just require these things easily.
Like I said in the other issue, WebpackER makes poor use of webpacks strengths. You are one of many having similar issues. Feel free to ask any follow-up questions, hope this helps!
Actually I can't really tell why I even have to use webpacker.. Maybe it makes more sense to use just webpack and remove the webpacker gem?
I think i understand your solution, but it still looks kinda dirty hack somehow :/ And actually the compiling performance is much better, since during changes you only have to compile your own code, not compile the 1MB file in total with all npm packages included.. At least this is the reason why I even do this - and which also happens now (-> compiling is pretty fast now).
And actually the compiling performance is much better, since during changes you only have to compile your own code, not compile the 1MB file in total with all npm packages included...(-> compiling is pretty fast now).
I and others have suggested this change, it's a shame to see webpack get such a bad rap from webpackER.
Actually I can't really tell why I even have to use webpacker...Maybe it makes more sense to use just webpack and remove the webpacker gem?
You don't, if you look around at other issues, I give better details on how you can resolve packs yourself from a manifest.json. Here is one such comment: https://github.com/rails/webpacker/issues/1903#issuecomment-464896525.

Think of removing training wheels from a bike, you can now take tighter turns at the cost of stability. In a similar way, it isn't webpackERs fault, it needs to be a zero-config tool for many different frameworks; the cost of that is speed & customization. This is why most JS frameworks include an "I know what I am doing" eject feature. Best of luck in finding the path that suits you best.
Most helpful comment
UPDATE:
It looks like Webpacker is expecting this JSON schema for _manifest.json_:
I'm not positive, but is that the CommonsChunk JSON schema?
Wepacker says it supports Webpack v4; however, the Webpack v4 documentation recommends using SplitChunksPlugin in combination with the ManifestPlugin (see here). The issue is, the ManifestPlugin doesn't output the manifest in the required schema, it uses the standard schema that
javascript_pack_tagexpects.