Skip to content

Backend MonacoEditor: "Identifier '_amdLoaderGlobal' has already been declared" when loader.js is included twice #6072

Description

@panki3a

Summary

On backend pages that use the Monaco code editor, the browser console throws:

loader.js:6 Uncaught SyntaxError: Identifier '_amdLoaderGlobal' has already been declared
(modules/backend/vuecomponents/monacoeditor/assets/vendor/monaco/vs/loader.js)

The editor still works (the first loader wins), but the second <script> fails to parse, leaving a noisy console error.

Environment

  • october/backend v4.3.1, october/system v4.3.1, october/rain v4.3.0
  • bundled Monaco loader 0.46.0
  • PHP 8.5

Root cause

Monaco 0.46's loader.js declares its globals with a top-level const in a classic (non-module) "use strict" script:

const _amdLoaderGlobal=this,_commonjsGlobal=typeof global=="object"?global:{};

A top-level const lands in the global lexical environment, so if loader.js is emitted as two separate <script> tags on the same document, the second parse throws already been declared. Older Monaco builds used var (idempotent on re-include), which is why this only surfaces after the 0.46 bump.

MonacoEditor::loadDependencyAssets() (modules/backend/vuecomponents/MonacoEditor.php) registers it once per request:

$this->addJs('vendor/monaco/vs/loader.js');

The duplicate appears to come from a second injection via the AJAX framework (e.g. a code-editor field rendered again inside a Repeater / partial update). The client-side asset de-duplication only skips a JS asset when a matching head script[src="…"] already exists, so a loader.js originally rendered in the page body (or under a slightly different URL) isn't recognised and gets appended a second time.

Suggested fix (either)

  • De-duplicate injected JS assets against the whole document rather than only head script[src]; or
  • Guard the AMD loader so a repeat include is a no-op (e.g. skip re-adding when window.require?.config already exists).

Repro

Open a backend form containing a codeeditor field that can be re-rendered via AJAX (e.g. inside a Repeater), trigger the partial update, and observe two loader.js <script> tags plus the SyntaxError in the console.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions