mirror of
https://github.com/electron/electron.git
synced 2026-05-02 03:00:22 -04:00
use cjs loader by default for preload scripts
This commit is contained in:
@@ -8,7 +8,7 @@ Sandboxed preload scripts are run as plain javascript without an ESM context. I
|
||||
|
||||
## Non-context-isolated renderers can't use Node.js ESM imports
|
||||
|
||||
If your renderer process does not have `contextIsolation` enabled you can not `import` ESM files via the Node.js module loader. This means that you can't `import('fs')` or `import('./foo')`. If you want to be able to do so you must enable context isolation. This is because in the renderer Chromium's `import()` function takes precedence and without context isolation there is no way for Electron to know which loader to route the request to.
|
||||
If your renderer process does not have `contextIsolation` enabled you can not `import()` ESM files via the Node.js module loader. This means that you can't `import('fs')` or `import('./foo')`. If you want to be able to do so you must enable context isolation. This is because in the renderer Chromium's `import()` function takes precedence and without context isolation there is no way for Electron to know which loader to route the request to.
|
||||
|
||||
If you enable context isolation `import()` from the isolated preload context will use the Node.js loader and `import()` from the main context will continue using Chromium's loader.
|
||||
|
||||
@@ -16,6 +16,10 @@ If you enable context isolation `import()` from the isolated preload context wil
|
||||
|
||||
Certain APIs in Electron (`app.setPath` for instance) are documented as needing to be called **before** the `app.on('ready')` event is emitted. When using ESM in the main process it is only guaranteed that the `ready` event hasn't been emitted while executing the side-effects of the primary import. i.e. if `index.mjs` calls `import('./set-up-paths.mjs')` at the top level the app will likely already be "ready" by the time that dynamic import resolves. To avoid this you should `await import('./set-up-paths.mjs')` at the top level of `index.mjs`. It's not just import calls you should await, if you are reading files asynchronously or performing other asynchronous actions you must await those at the top-level as well to ensure the app does not resume initialization and become ready too early.
|
||||
|
||||
## Node.js preload scripts will not run synchronously on pages with no content
|
||||
## Node.js ESM Preload Scripts will run before page load on pages with no content
|
||||
|
||||
If the response body for the page is **completely** empty. I.e. `Content-Length: 0` the preload script will not block the page load. This is an extreme edge case and if this impacts you you should just change your response body to have _something_ in it, we recommend an empty `html` tag (`<html></html>`).
|
||||
If the response body for the page is **completely** empty, i.e. `Content-Length: 0`, the preload script will not block the page load, which may result in race conditions. If this impacts you, change your response body to have _something_ in it, for example an empty `html` tag (`<html></html>`) or swap back to using a CommonJS preload script (`.js` or `.cjs`) which will block the page load.
|
||||
|
||||
## ESM Preload Scripts must have the `.mjs` extension
|
||||
|
||||
In order to load an ESM preload script it must have a `.mjs` file extension. Using `type: module` in a nearby package.json is not sufficient. Please also not the limitation above around not blocking page load if the page is empty.
|
||||
|
||||
@@ -127,12 +127,27 @@ const { appCodeLoaded } = process;
|
||||
delete process.appCodeLoaded;
|
||||
|
||||
const { preloadPaths } = ipcRendererUtils.invokeSync<{ preloadPaths: string[] }>(IPC_MESSAGES.BROWSER_NONSANDBOX_LOAD);
|
||||
if (preloadPaths.length) {
|
||||
const cjsPreloads = preloadPaths.filter(p => path.extname(p) !== '.mjs');
|
||||
const esmPreloads = preloadPaths.filter(p => path.extname(p) === '.mjs');
|
||||
if (cjsPreloads.length) {
|
||||
// Load the preload scripts.
|
||||
for (const preloadScript of cjsPreloads) {
|
||||
try {
|
||||
Module._load(preloadScript);
|
||||
} catch (error) {
|
||||
console.error(`Unable to load preload script: ${preloadScript}`);
|
||||
console.error(error);
|
||||
|
||||
ipcRendererInternal.send(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, preloadScript, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (esmPreloads.length) {
|
||||
const { loadESM } = __non_webpack_require__('internal/process/esm_loader');
|
||||
|
||||
loadESM(async (esmLoader: any) => {
|
||||
// Load the preload scripts.
|
||||
for (const preloadScript of preloadPaths) {
|
||||
for (const preloadScript of esmPreloads) {
|
||||
await esmLoader.import(pathToFileURL(preloadScript).toString(), undefined, Object.create(null)).catch((err: Error) => {
|
||||
console.error(`Unable to load preload script: ${preloadScript}`);
|
||||
console.error(err);
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('contextBridge', () => {
|
||||
before(async () => {
|
||||
server = http.createServer((req, res) => {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('<html></html>');
|
||||
res.end('');
|
||||
});
|
||||
serverUrl = (await listen(server)).url;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user