{"record":{"id":"5c8ebbb733b587c6","repo":"laurent22/joplin","slug":"all-plugins-must-have-a-function-default-export","errorCode":null,"errorMessage":"All plugins must have a function default export","messagePattern":"All plugins must have a function default export","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/editor/CodeMirror/pluginApi/PluginLoader.ts","lineNumber":139,"sourceCode":"\t\t\t\tstyleContainer.appendChild(style);\n\t\t\t}\n\n\t\t\tthis.pluginScriptsContainer.appendChild(styleContainer);\n\t\t};\n\n\t\tthis.pluginRemovalCallbacks[contentScriptToId(plugin)] = () => {\n\t\t\tfor (const callback of onRemoveCallbacks) {\n\t\t\t\tcallback();\n\t\t\t}\n\n\t\t\tthis.loadedContentScriptIds = this.loadedContentScriptIds.filter(id => {\n\t\t\t\treturn id !== contentScriptToId(plugin);\n\t\t\t});\n\t\t};\n\n\t\taddScript(async exports => {\n\t\t\tif (!exports?.default || !(typeof exports.default === 'function')) {\n\t\t\t\tthrow new Error('All plugins must have a function default export');\n\t\t\t}\n\n\t\t\tconst context = {\n\t\t\t\tpostMessage: plugin.postMessageHandler,\n\t\t\t\tpluginId: plugin.pluginId,\n\t\t\t\tcontentScriptId: plugin.contentScriptId,\n\t\t\t};\n\t\t\tconst loadedPlugin = exports.default(context) ?? {};\n\n\t\t\tloadedPlugin.plugin?.(this.editor);\n\n\t\t\tif (loadedPlugin.codeMirrorOptions) {\n\t\t\t\tfor (const key in loadedPlugin.codeMirrorOptions) {\n\t\t\t\t\tthis.editor.setOption(key, loadedPlugin.codeMirrorOptions[key]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (loadedPlugin.assets) {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/editor/CodeMirror/pluginApi/PluginLoader.ts#L121-L157","documentation":"Thrown by the CodeMirror 6 PluginLoader when a content script's evaluated module exports either no default or a default that is not a function. The loader contract (see addScript at line 137) requires every CodeMirror content script to export a default function that receives a context object { postMessage, pluginId, contentScriptId } and returns the plugin descriptor. This mirrors Joplin's content-script API for the CodeMirror editor.","triggerScenarios":"The content script's bundled entry exports a named export instead of default; the default export is an object or class instance rather than a function; the script failed to assign module.exports.default due to a bundler misconfiguration (e.g. libraryTarget not set to produce a default export); the script threw before assigning exports.","commonSituations":"Plugin author wrote `export const plugin = ...` instead of `export default ...`; webpack libraryTarget/commonjs misconfiguration in the plugin's extra-script config; the content script was transpiled such that default is wrapped (e.g. __esModule default re-export); a port from CodeMirror 5 that used a different export shape.","solutions":["Ensure the content script entry has exactly: export default (context) => { return { plugin, assets, codeMirrorOptions }; }.","Check the plugin's webpack output config uses libraryTarget: 'commonjs' and libraryExport: 'default' for extra scripts (see resolveExtraScriptPath in webpack.config.js).","Inspect the built JS in /dist to confirm module.exports.default is a function.","If migrating from CM5, rewrite the entry to the function-default contract."],"exampleFix":"// before (content script)\nexport const plugin = (editor) => { /* ... */ };\n// after\nexport default ({ postMessage, pluginId, contentScriptId }) => {\n\treturn {\n\t\tplugin: (editor) => { /* ... */ },\n\t};\n};","handlingStrategy":"type-guard","validationCode":"// Validate the content script's default export shape in plugin tests\nconst exports = require('./src/index');\nif (typeof exports.default !== 'function') {\n  throw new Error('Content script must export a default function');\n}","typeGuard":"function isValidContentScript(exports) {\n  return !!exports && typeof exports.default === 'function';\n}","tryCatchPattern":"try {\n  loader.setPlugins(contentScripts);\n} catch (e) {\n  if (/function default export/.test(e.message)) {\n    // flag the offending plugin to the user, skip loading it\n  } else throw e;\n}","preventionTips":["Always author content scripts as: export default (ctx) => ({ ... }).","Set webpack libraryTarget: 'commonjs', libraryExport: 'default' for extra scripts.","Inspect /dist output to confirm module.exports.default is a function before packaging."],"tags":["editor","codemirror","plugin","content-script","typescript"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}