Skip to content

Shared modules between targets since 2.14.0 #10154

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

Open
Yhraen opened this issue May 12, 2025 · 3 comments
Open

Shared modules between targets since 2.14.0 #10154

Yhraen opened this issue May 12, 2025 · 3 comments

Comments

@Yhraen
Copy link

Yhraen commented May 12, 2025

🐛 bug report

Hi there 👋

As stated in the documentation (https://parceljs.org/languages/html/#inline-scripts-and-styles) inline scripts and imports inside an HTML file are inlined into it when generating bundles.

However, this behavior has changed since version 2.14.0.
It no longer is fully inlined if multiple targets with the same context (at least for browser context, i didn't test the others) are importing the same module inside of the HTML file.
The common module is then optimized away : split to his own bundle and shared between targets (subsequent targets referencing files from the first target 😨).

This contradict the documentation and do not seems to make sense across targets.

This also is an issue outside of inlining : modules are splitted and shared across targets within the same context anyway.

🎛 Configuration (.babelrc, package.json, cli command)

package.json

{
	"targets": {
		"target_1": {
			"source": "src/target_1.html"
		},
		"target_2": {
			"source": "src/target_2.html"
		}
	},
	"dependencies": {
		"yet_another_external_lib": "1.0.0"
	},
	"devDependencies": {
		"@parcel/core": "2.15.0",
		"parcel": "2.15.0"
	},
}

src/target_1.html

<!doctype html>
<html lang="fr">
<head>
  <title>Target 1</title>
  <meta charset="UTF-8" />
  <script type="module">
    import "yet_another_external_lib";
  </script>
</head>
<body>
  <h1>Target 1</h1>
</body>
</html>

src/target_2.html

<!doctype html>
<html lang="fr">
<head>
  <title>Target 2</title>
  <meta charset="UTF-8" />
  <script type="module">
    import "yet_another_external_lib";
  </script>
</head>
<body>
  <h1>Target 2</h1>
</body>
</html>

🤔 Expected Behavior

The inline script should be fully inlined for every target, as it was prior to version 2.14.0.

i.e. the result of the parcel build command should be something like this :

✨ Built in 200ms

build/static/target_1/target_1.html            100 kB    100ms
build/static/target_2/target_2.html            100 kB    100ms

😯 Current Behavior

The common imported module is split and shared.

i.e. the result of the parcel build command is something like this :

✨ Built in 300ms

build/static/target_1/target_1.html                       10 kB    100ms
build/static/target_1/target_1.68536a5c.js                90 kB    100ms
build/static/target_2/target_2.html                       10 kB    100ms

The common module is imported in each bundle as import "../target_1/target_1.68536a5c.js";

🌍 Your Environment

Software Version(s)
Parcel since 2.14.0
Node 22.14.0
Yarn 4.9.1
Operating System arch

Anyway, working with Parcel has always been a breeze, thanks for the good work 🙏

@devongovett
Copy link
Member

Wouldn't that result in duplicate modules in each script tag leading to a larger size HTML file? Why do you need it to be fully inlined multiple times?

@Yhraen
Copy link
Author

Yhraen commented May 15, 2025

I need it to be inlined in my usecase because I'm generating several dynamic API documentations that are indeed going to be deployed on an HTTP server, but should also be easily shareable and useable locally. A simple standalone HTML file (one for each API) does the trick, hence the need for inlining.

But regardless of this usecase, the fact that the documented way to manually enforce inlining doesn't enforce anything under some circumstances already seems like a problem in itself.

Moreover, inlining or not, in the context of different targets (with different source files !) I don't think it can really be considered as an optimization, at least not without making unreasonable assumptions about the way these bundles will be deployed.

Client-wise, this won't really change anything for a given target. The total amount of data downloaded will more or less be exactly the same.

Server-wise, you now cannot safely deploy a target bundle alone as it could reference files from any other target's bundle (target_3 can directly reference files from target_1 and target_2; which looks like a big no-no to me) . You end up having to deploy every targets together every time if you don't want to have to check for shared modules and cherry pick anything. And that's assuming you know that targets can potentially not be independent as this behavior isn't exactly self-explanatory and expected. You can easily miss it in the cli output (especially with large and complex bundles) and discover it later when things will break after deploying a specific target on a specific server.

This will only be an optimization if you assume that every targets will be deployed together and be served from the very same origin (and assuming there is no need for access restrictions between these ressources otherwise it will add yet another thing to handle specifically because of this behavior) and that a given client is going to access more than one target, so that these shared modules will then be fetched from the cache for subsequent targets. But I don't think that making this assumption should fall under the bundler's responsibility.

Imho, each target's bundle should be totally independent (as it was prior to 2.14.0), and introducing dependencies between them kinda only implies cons if you do not make specific assumptions about the deployment context.

@devongovett
Copy link
Member

Targets need to be able to have dependencies between them. For example with React Server Components, the server and client have dependencies on each other.

the fact that the documented way to manually enforce inlining doesn't enforce anything

I don't see anything in the docs that says that inline bundles cannot have shared bundles.

You could try disabling shared bundles though. In your package.json:

{
  "@parcel/bundler-default": {
    "disableSharedBundles": true
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants