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.
Summary
On backend pages that use the Monaco code editor, the browser console throws:
The editor still works (the first loader wins), but the second
<script>fails to parse, leaving a noisy console error.Environment
Root cause
Monaco 0.46's
loader.jsdeclares its globals with a top-levelconstin a classic (non-module)"use strict"script:A top-level
constlands in the global lexical environment, so ifloader.jsis emitted as two separate<script>tags on the same document, the second parse throwsalready been declared. Older Monaco builds usedvar(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: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 aloader.jsoriginally rendered in the page body (or under a slightly different URL) isn't recognised and gets appended a second time.Suggested fix (either)
head script[src]; orwindow.require?.configalready exists).Repro
Open a backend form containing a
codeeditorfield that can be re-rendered via AJAX (e.g. inside a Repeater), trigger the partial update, and observe twoloader.js<script>tags plus the SyntaxError in the console.