parcel
parcel copied to clipboard
Feature request: local context for entrypoints
🙋 feature request
local
or browser-local
entrypoint context for environments that load scripts locally.
🤔 Expected Behavior
If entrypoint has a local
context, the script elements in the HTML page output should have neither type="module"
nor nomodule
attributes.
😯 Current Behavior
The HTML page fails to load both the type="module"
script and the nomodule
script. This is because the browser supports JS modules but there is no server serving the JS files, resulting in a CORS error or invalid MIME error.
💁 Possible Solution
If entrypoint has "context": "local"
, don't use type="module"
and nomodule
, just use the "fallback" script with type="text/javascript"
attribute on the HTML element.
🔦 Context
I have an application that runs on specific hardware using a chromium browser locally and functions similarly to electron - uses an HTML entrypoint and necessary assets are fetched locally.
JS modules are supported by the chromium version but I get the error Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
because there is no server serving the JS files, they are only being loaded from the filesystem.
I've tried using "context": "electron-renderer"
, but this gives the same HTML output as "context": "browser"
. The only workarounds I could find were manually changing the HTML output and inlining the entire JS bundle (~1MB) which are not optimal.
The only similar issue I could find was this discussion.
💻 Examples
Build using parcel using an HTML entrypoint that has a JS script element and try to open the resulting HTML in the browser.
Did I understand you correctly that you want to view/run the output from Parcel via a file://
url without a werbserver?
Did I understand you correctly that you want to view/run the output from Parcel via a
file://
url without a werbserver?
Yes
@mischnic differential bundling gives a fallback bundle and that works if I just remove the nomodule
on it
This is duplicated by https://github.com/parcel-bundler/parcel/issues/7959. Commenting here because this is still open.
I would like support for bundling for the file:///
procotol, but I actually prefer the possible solution from the duplicate feature request; a CLI flag. The advantage of a CLI flag is that it allows a project to be bundled for different usecases (e.g. for file:///
protocol or for a web server) without changing any configuration.
I've created a workaround in the following repo. https://github.com/NothingEverWorks/parcel-local-html
The workaround fixes the script tags after bundling by using the nomodule index.js output from the differential bundling, that already works with the file:///
procotol and supports synchronous import
!
That would be great :+1:
Thanks a lot @NothingEverWorks for the inspiration. I had to adapt a the script for my use case but I can finally have a full automatic pipeline for the game GUI without having to manually modify the file.
Do you mind it if I package your idea in a new repository that -should- cover most use cases for the game and maintain it ?
I had to google way to much to find this !
Parcel removing type="module"
from script tags also means that you cannot using top-level async calls, instead one has to wrap them manually.
Parcel sells itself as the works-out-of-the-box alternative to webpack and then does stuff like this where it completely subverts basic expectations such as leaving type="module"
intact.
Top level await: #4028
Leaving type="module"
wouldn't fix that anyway, since modules are wrapped in a function in order to be bundled, therefore the await wouldn't be top-level anymore.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.
This issue still persists, can it be reopened? I'm hitting the lack of apparent support for local-filesystem JavaScript due to magic that was being done before but isn't now.
At the least, the migration document could do more to explain how to change things for this use-case.
@parcel/transformer-js: Browser scripts cannot have imports or exports.
D:\code\pso-tracker\src\index.js:1:1
> 1 | import PaletteProfiles from './modules/PaletteProfiles';
.
.
.
💡 Add the type="module" attribute to the <script> tag.
The hint is useless because I run into CORS problems with running a local file.
A workaround I found is to change to a more raw form of import.
var PaletteProfiles;
import('./modules/PaletteProfiles.js').then((x) => { PaletteProfiles = x.default; })
This worked for importing data. When dealing with a class, I did not have success in shipping the class outside of the then
callback directly ("x
is not a constructor"), but another workaround sufficed because I just needed to instantiate the class immediately and only once anyway.
Before
import SaveData from './modules/SaveData';
var saveContainer = new SaveData(localStorage);
After
var saveContainer;
import('./modules/SaveData.js').then((x) => { saveContainer = new x.default(localStorage); })
For classes that needed instantiation later and multiple instances, this was trickier, as I had to make another scaffholding constructor function and store a lambda function off that passed in parameters, so that the scaffholding could use the exported default class.
Considering this worked in Parcel 1 with "nice module syntax", it'd be good to have this option, as the local web app was my only target. My workaround still has other issues to figure out and I'm not optimistic that I'll have a clean solution when it's done.