-
-
Notifications
You must be signed in to change notification settings - Fork 26.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disabling code splitting in CRA2 #5306
Comments
Can you provide more details about what you’re trying to do and why? |
Hi @gaearon, I hope I'm not hijacking this thread, but we've run into a similar question. We are mixing CRA with legacy JS. We have certain code that we have to run synchronously before the legacy JS because we have to make it available to our legacy application. In CRA1 would add code like that to |
Sorry, it’s still not quite clear to me what you mean. An example reproducing the problem would be valuable. |
I can work on a minimal reproduction case. |
Actually, I missed the part about the runtime. I'm looking at the generated <script src="/ui/static/js/53.4ef0ec74.chunk.js"></script>
<script src="/ui/static/js/main.384085f8.chunk.js"></script> But right now in our product we've only added the |
I don't understand what "added" means. If you have a separate HTML file you create manually (instead of using our HTML output), you can construct it with information in |
Sorry, yeah, by added I just mean that we have custom HTML with a script tag for |
It seems like we should put more info in |
Is there any way to do this? I work on cancer.gov and we have an embedded widget made in CRA that needs to be a single file for the current build and deployment system to work (I've already been having to overrride the automated hashing with react-app-rewired). |
I should add that the issue is caused in part by a peculiarity of our setup. The CRA based app is hosted in a separate repo from cancer.gov as source code (to allow for it to be used on other sites as well) which requires it as a dependency directly from github (so a post-install script has to run to build the CRA app inside of cancer.gov). When we updated webpack to version 4 on cgov, the CRA v1 app stopped working (assumedly because it was being built inside of cgov's node_modules causing some issues with the conflicting webpack versions), so in trying to update to CRA2, I've managed to work around almost every issue except the code splitting. At the end of the day, on cgov, we are requiring the CRA based widget as a library, so I want to be able to output a single file or at least require the package with static filenames. |
asset-manifest entries like: |
Yes, it would be nice if you add an environment variable to opt out of code splitting. I'm developing an app, which works like an embeddable widget - it doesn't render itself by default, it just adds a global object with some API, which should be used by an eventual user to render the widget to any tag he wishes to embed it. Consequently, I'm not interested in the default html output at all, I need only the final bundles of js and css files. Formerly, CRA 1.x produced only 1 js and 1 css files and it was convenient. But now, with CRA 2.x, there are 3 js files, and in order to use the app, an eventual user should include 3 js files instead of one. Or I have to copy them all into one file (I haven't tried it yet). Thus, I would like to have an opportunity to return to the previous behavior, namely, to have only 1 js and 1 css file as the output. |
+1 on the environment variable to opt out of splitting. I'm just trying to build a JS bundle for a Wordpress site, while leaving my CRA bundle in a CDN. It's not possible to update wordpress for every CRA JS update, and i ended up having to do this to load my bundle from my wordpress site:
|
Hey @gaearon, we have this issue as well. We need to disable the code splitting because we live inside a Rails app and for now we need to ship a single file. I read your suggestion about using But I have two concerns about it.
Since this is already done with the Webpack build step when you create the final HTML file, I am assuming that there is some code somewhere in the dependencies that I could give an asnwer my second question, would be helpful if you share a link to it if you know where it lives. I am trying to find it as I am typing this. |
+1 for me too. Same issue, currently phasing in React into a legacy app and the multiple JS files mess with the legacy setup. I understand wanting to educate developers as to best practices, but it would be nice if the option to opt out of code splitting was there, perhaps buried deep somewhere but there nevertheless. Thanks for the great work as always! |
For those of you who want to disable default chunking/code splitting in cra-2 so it bundled and ran from a single file, then you can disable caching within webpack.config by adding the following:
You can also disable the long term caching just below by commenting out, or setting the runtimeChunk to false.
|
@timclifford Did I understand correctly that you suggest us to do If you suggest us to eject, it's not an option. Or, speaking differently, it's an option, of course, but not the one we want. |
@RussCoder I was yes, providing an option only for those who have ejected the project already. |
+1 This is also a problem for us. We have to embed our output onto a WP site, so having a single output makes a ton of sense. This sounds like a great option to add as a toggle based on an environment variable during build. |
See #4632 for this also. I think the way CRA2 does things out of the box, chunking included, is great. The problem comes when we have to deploy to third party systems we don't have control over. The system I'm deploying to knows how to read the |
Just thought I'd post my temporary solution to this in case it helps anyone. A bit hacky, but at least one doesn't have to eject:
Save that as build-non-split.js or whatever and amend your package.json like:
|
@vonkanehoffen This workaround is a lifesaver for me. THANK YOU! |
Also, if you're using react-app-rewired, in your module.exports = function override(config) {
config.optimization.runtimeChunk = false;
config.optimization.splitChunks = {
cacheGroups: {
default: false
}
};
return config;
}; And if you happen to require the bundle js directly for testing (usually from another project), like this: <script src="http://localhost:3000/static/js/bundle.js"></script> You have to include a bit more now: <script src="http://localhost:3000/static/js/bundle.js"></script>
<script src="http://localhost:3000/static/js/0.chunk.js"></script>
<script src="http://localhost:3000/static/js/main.chunk.js"></script> (edit: also just fyi, as of this writing, |
@vonkanehoffen THANKS |
@vonkanehoffen TIL you can do that...brilliant. This seems like the right amount of tinkering with the default react-scripts sources. The same can be done for the start.js as well. |
@gupta-ji6 Thanks for the response! I have the exact same dependency versions as you, and yes I'm using I'm not sure what I'm doing wrong, since as I mentioned We are trying to use multiple entry points as described here: https://blog.logrocket.com/multiple-entry-points-in-create-react-app-without-ejecting/. I removed all of that code now when testing though |
@vjsingh I see. Maybe try opening an issue on craco repo to get help in resolving this. |
@gupta-ji6 Filed - dilanx/craco#248 Thank you! |
@gupta-ji6 @rutikwankhade @leoloso Any chance you know what's going on here. Your configuration makes sense, but it's not working for me for some reason and I'm stumped. Dependencies: // craco.config.js
const { whenProd, POSTCSS_MODES } = require("@craco/craco");
const InlineChunkHtmlPlugin = require("react-dev-utils/InlineChunkHtmlPlugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const findRule = (rules, matcher) => {
for (const rule of rules) {
if (Array.isArray(rule.oneOf)) {
return findRule(rule.oneOf, matcher);
}
if (rule.test && matcher.match(rule.test)) {
if (!rule.exclude || !matcher.match(rule.exclude)) {
return rule;
}
}
}
return undefined;
};
const replaceLoader = (rule, matchLoaderString, replacement) => {
if (!rule.use) {
return;
}
const loaderIndex = rule.use.findIndex((definition) =>
typeof definition === "string"
? matchLoaderString === definition
: matchLoaderString === definition.loader
);
rule.use[loaderIndex] = replacement;
};
module.exports = {
style: {
postcss: {
mode: POSTCSS_MODES.file,
},
},
webpack: {
configure: {
output: {
filename: "static/js/[name].bundle.js",
},
optimization: {
runtimeChunk: false,
splitChunks: {
chunks() {
return false;
},
},
},
},
},
plugins: [
{
plugin: {
overrideWebpackConfig: ({ webpackConfig }) => {
whenProd(() => {
// Remove InlineChunkHtmlPlugin because we don't want/have chunks
const inlineChunkHtmlPluginIndex = webpackConfig.plugins.findIndex(
(plugin) => plugin.constructor.name === InlineChunkHtmlPlugin.name
);
webpackConfig.plugins.splice(inlineChunkHtmlPluginIndex, 1);
// Remove MiniCssExtractPlugin so they are bundled in JS
const miniCssExtractPluginIndex = webpackConfig.plugins.findIndex(
(plugin) => plugin.constructor.name === MiniCssExtractPlugin.name
);
webpackConfig.plugins.splice(miniCssExtractPluginIndex, 1);
// Replace the MiniCssExtractPlugin.loader with style-loader for .css rule
replaceLoader(
findRule(webpackConfig.module.rules, "index.css"),
MiniCssExtractPlugin.loader,
require.resolve("style-loader")
);
// Replace the MiniCssExtractPlugin.loader with style-loader for .module.css rule
replaceLoader(
findRule(webpackConfig.module.rules, "index.module.css"),
MiniCssExtractPlugin.loader,
require.resolve("style-loader")
);
console.log("webpackconfig", webpackConfig);
});
return webpackConfig;
},
},
options: {},
},
],
}; Output:
I am using typescript.. not sure if that plays into it? |
FWIW I also just created a brand new project and only did the following:
// craco.config.js
module.exports = {
webpack: {
configure: {
output: {
filename: "static/js/[name].js",
},
optimization: {
runtimeChunk: false,
splitChunks: {
chunks(chunk) {
return false;
},
},
},
},
},
plugins: [
{
plugin: {
overrideWebpackConfig: ({ webpackConfig }) => {
webpackConfig.plugins[5].options.filename = "static/css/[name].css";
return webpackConfig;
},
},
options: {},
},
],
}; And the output is: Compiled successfully.
File sizes after gzip:
42.47 KB build/static/js/main.js
1.59 KB build/static/js/1.635bd783.chunk.js
518 B build/static/css/main.css EDIT: I found the problem. I started to inspect the chunk that was generated and I noticed that the contents where entirely coming from the default included import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
}); Which is forcing a chunk to be formed. So, the solution is to remove it from the index.js file completely and it will not generate an extra chunk. Or just leave it there and don't reference it in w/e production build pipeline you have. |
Actually, |
I had trouble with all of the above solutions, so my hacky solution was to read the manifest, and just concat the JS files together myself.
const { exec } = require('child_process');
const assetManifest = require('../build/asset-manifest.json');
const files = assetManifest.entrypoints.filter((path) => path.endsWith('js')).map((path) => `build/${path}`).join(' ');
console.log(`Joining ${files}`);
// Just shorthand for joining with a newline between the files
exec(`awk 1 ${files} > dist/build/static/js/bundle.min.js`); Then, in my "scripts": {
"start": "react-scripts start",
"build": "npm run build:react && npm run build:bundle",
"build:react": "react-scripts build",
"build:bundle": "node scripts/build-bundle.js",
"test": "react-scripts test",
"eject": "react-scripts eject"
}, |
This worked great! I modified it a little to find MiniCssExtractPlugin by name in case the CRA webpack config plugin order changes in the future. plugins: [
{
plugin: {
overrideWebpackConfig: ({ webpackConfig }) => {
const miniCssExtractPluginIndex = webpackConfig.plugins.findIndex(
(plugin) => plugin.constructor.name === 'MiniCssExtractPlugin'
);
if (miniCssExtractPluginIndex > -1) {
webpackConfig.plugins[miniCssExtractPluginIndex].options.filename =
'static/css/[name].css';
}
return webpackConfig;
},
},
options: {},
},
], |
no issues - updates Portal build script to use rewired react-scripts config - updated config handles css embed as well as output location/name for portal bundle as part of cra build - makes extra webpack bundling redundant for now - updates dev mode to map the portal source map useful for testing build version locally - updates custom webpack config with copy plugin for future use refs - facebook/create-react-app#5306 (comment) https://gist.github.com/phdesign/3fd306db2bc53f6368e6f0f73bbeff19
no issues - updates Portal build script to use rewired react-scripts config - updated config handles css embed as well as output location/name for portal bundle as part of cra build - makes extra webpack bundling redundant for now - updates dev mode to map the portal source map useful for testing build version locally - updates custom webpack config with copy plugin for future use refs - facebook/create-react-app#5306 (comment) https://gist.github.com/phdesign/3fd306db2bc53f6368e6f0f73bbeff19
Hey @jpgilchrist & @teddybradford i just added this miniCssExtractPluginIndex change:
but i get
Thats what
EDIT: ok i've tested it now with a plain new CRA project + CRACO and it does seem to work. HOWEVER when i use
This doesn't seem to work and i get the above error:
|
@avgurf I had a similar issue to you today, and I believe it is from the following lines:
What I think you want to do is just change Perhaps try something like...
Or something similar. I had a bug like that, and until I worked out and corrected the problem, I had the same result as you. |
Not required to do until 2023 but hey why not. The extension can no longer use the sha-256 manifest hash in the content security policy, so use craco (Create React App Config Override) to bundle the app into a single main.js instead of inline. Also change "browser_action" to "action". The craco.config.js config file was sourced from the reference below. Reference: facebook/create-react-app#5306
no issues - updates Portal build script to use rewired react-scripts config - updated config handles css embed as well as output location/name for portal bundle as part of cra build - makes extra webpack bundling redundant for now - updates dev mode to map the portal source map useful for testing build version locally - updates custom webpack config with copy plugin for future use refs - facebook/create-react-app#5306 (comment) https://gist.github.com/phdesign/3fd306db2bc53f6368e6f0f73bbeff19
For anyone coming here in 2023, none of the above worked for me with CRA@5.0.1, which, as the PR above notes, ships with webpack5, but this did, straight from the webpack docs (override set with config.plugins = [
...config.plugins,
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
]; |
it's better to use Vite |
cool story |
works perfect but remember to put npx at build: also if you want to remove hash from js file, put this: |
The above solutions didn't work for me - I think rewired has changed since. This is my solution (March 2023) with react-rewired.
|
Honestly, the best bet for this is to just use vite. It doesn't obfuscate anything and is incredibly easy to setup. I have had so much success with it and it's brought me so much satisfaction. |
@Theromantus CRACO + LimitChunkCountPlugin solution worked for me. This is my craco.config.js file content:
Tested using @craco/craco@7.1.0 and react-scripts@5.0.1 |
please stop using |
* Add `disableChunk` Function to disable chunk or code splitting, see: facebook/create-react-app#5306 for more info * fix: export disable chunk function
How can I disable the code splitting in CRA 2?
The text was updated successfully, but these errors were encountered: