Skip to content

Commit 1ed74fa

Browse files
committed
Merge branch 'main' of https://github.com/NotePlan/plugins
2 parents 3dd69c4 + 7c2a7a6 commit 1ed74fa

File tree

3 files changed

+134
-4
lines changed

3 files changed

+134
-4
lines changed

np.installer/plugin.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"noteplan.minAppVersion": "3.3",
3+
"plugin.id": "np.installer",
4+
"plugin.name": "⬇️ Plugin Installer",
5+
"plugin.description": "Install plugins right from the command bar. This is a core plugin and can't be deleted.",
6+
"plugin.icon": "",
7+
"plugin.author": "",
8+
"plugin.repoUrl": "CorePlugins",
9+
"plugin.version": "0.1",
10+
"plugin.dependencies": [],
11+
"plugin.script": "script.js",
12+
"plugin.isRemote": "false",
13+
"plugin.hidden": true,
14+
"plugin.commands": [
15+
{
16+
"name": "install plugin",
17+
"description": "Load a list of plugins and lets you install one",
18+
"jsFunction": "installPlugins"
19+
},
20+
{
21+
"name": "development install",
22+
"description": "Load a list of plugins and lets you install one, including hidden ones",
23+
"jsFunction": "installPluginsIncludingHidden"
24+
},
25+
],
26+
"plugin.preferences": []
27+
}

np.installer/script.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
async function installPluginsIncludingHidden() {
3+
_installPlugins(true)
4+
}
5+
6+
async function installPlugins() {
7+
_installPlugins(false)
8+
}
9+
10+
async function _installPlugins(showHidden) {
11+
let plugins = await DataStore.listPlugins(true, showHidden)
12+
13+
let list = plugins.map(p => pluginToDescription(p))
14+
list.push("❌ Cancel")
15+
16+
let selection = await CommandBar.showOptions(list, "Select a plugin to install/update:")
17+
18+
if(selection.index < plugins.length) {
19+
let plugin = plugins[selection.index]
20+
try {
21+
let result = await DataStore.installPlugin(plugin, true)
22+
23+
let list = ["✅ OK", "📖 Open Readme", "", "Commands:"]
24+
plugin.commands.forEach((item, i) => {
25+
list.push("/" + item.name + " - " + item.desc)
26+
});
27+
28+
let selection = await CommandBar.showOptions(list, "Successfully installed '" + plugin.name + "'")
29+
if(selection.index == 1) {
30+
CommandBar.openURL(plugin.repoUrl)
31+
}
32+
} catch(err) {
33+
await CommandBar.showOptions(["✅ OK"], "Error: " + err)
34+
}
35+
}
36+
}
37+
38+
function pluginToDescription(p) {
39+
let installed = p.isOnline ? "" : ", installed: 🆗"
40+
41+
if(p.availableUpdate) {
42+
installed += ", update: v" + p.availableUpdate.version + " 🆕"
43+
}
44+
45+
return p.name + " (v" + p.version + installed + ")"
46+
}

scripts/rollup.generic.js

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const path = require('path')
2+
const fs = require('fs')
23
const notifier = require('node-notifier')
34
const colors = require('chalk')
45
const messenger = require('@codedungeon/messenger')
@@ -142,6 +143,63 @@ function getRollupConfig(options) {
142143

143144
const exportedFileVarName = options.bundleName || 'reactBundle'
144145

146+
// Validate entry file exports before building
147+
const isRootBundle = exportedFileVarName.includes('Root') || exportedFileVarName.includes('RootBundle')
148+
try {
149+
const entryFileContent = fs.readFileSync(entryPointPath, 'utf8')
150+
151+
if (isRootBundle) {
152+
// Root bundles should export React and ReactDOM
153+
const hasReact = /export\s+.*\bReact\b/.test(entryFileContent) || /export\s*\{[^}]*\bReact\b/.test(entryFileContent)
154+
const hasReactDOM = /export\s+.*\bReactDOM\b/.test(entryFileContent) || /export\s*\{[^}]*\bReactDOM\b/.test(entryFileContent)
155+
156+
if (!hasReact || !hasReactDOM) {
157+
throw new Error(
158+
`\n❌ ROLLUP VALIDATION ERROR: Root bundle entry file "${opts.entryPointPath}" is missing required exports.\n\n` +
159+
`Root bundles must export React and ReactDOM for other bundles to use.\n\n` +
160+
`Expected exports in your entry file:\n` +
161+
` - React (from 'react')\n` +
162+
` - ReactDOM (from 'react-dom')\n\n` +
163+
`Example entry file:\n` +
164+
` export { default as React } from 'react'\n` +
165+
` export { default as ReactDOM } from 'react-dom'\n` +
166+
` export { createRoot } from 'react-dom/client'\n` +
167+
` // ... other exports\n\n` +
168+
`Entry file: ${entryPointPath}\n`
169+
)
170+
}
171+
} else {
172+
// Non-Root bundles should export WebView
173+
const hasWebView = /export\s+.*\bWebView\b/.test(entryFileContent) ||
174+
/export\s*\{[^}]*\bWebView\b/.test(entryFileContent) ||
175+
/export\s*\{[^}]*as\s+WebView/.test(entryFileContent)
176+
177+
if (!hasWebView) {
178+
throw new Error(
179+
`\n❌ ROLLUP VALIDATION ERROR: Entry file "${opts.entryPointPath}" is missing required WebView export.\n\n` +
180+
`All React component bundles (except Root) must export a component named "WebView".\n` +
181+
`This is what the Root component expects to load dynamically.\n\n` +
182+
`To fix this, update your entry file to export your component as WebView:\n\n` +
183+
`Option 1: Export your component as WebView directly:\n` +
184+
` export { YourComponent as WebView } from './YourComponent.jsx'\n\n` +
185+
`Option 2: If your component is already named WebView:\n` +
186+
` export { WebView } from './YourComponent.jsx'\n\n` +
187+
`Example entry file (rollup.YourComponent.entry.js):\n` +
188+
` // Root expects a component called WebView\n` +
189+
` export { YourComponent as WebView } from '../components/YourComponent.jsx'\n\n` +
190+
`Entry file: ${entryPointPath}\n` +
191+
`Bundle name: ${exportedFileVarName}\n`
192+
)
193+
}
194+
}
195+
} catch (error) {
196+
if (error.code === 'ENOENT') {
197+
throw new Error(`Entry file not found: ${entryPointPath}`)
198+
}
199+
// Re-throw validation errors
200+
throw error
201+
}
202+
145203
// Map external module names to their global variable names
146204
// React and ReactDOM are loaded by np.Shared's Root component
147205
const externalGlobals = (externalModules || []).reduce((acc, cur) => {
@@ -274,10 +332,9 @@ function getRollupConfig(options) {
274332
// Assign bundle to global
275333
footer = `Object.assign(typeof(globalThis) == "undefined" ? this : globalThis, ${exportedFileVarName});`
276334

277-
// Extract WebView to global scope (Root component expects it as a global)
278-
if (exportedFileVarName.includes('FormView') || exportedFileVarName.includes('FormBuilderView')) {
279-
footer += `\nif (typeof ${exportedFileVarName} !== 'undefined' && ${exportedFileVarName}.WebView) { typeof(globalThis) == "undefined" ? (this.WebView = ${exportedFileVarName}.WebView) : (globalThis.WebView = ${exportedFileVarName}.WebView); }`
280-
}
335+
// Extract WebView to global scope if it exists (Root component expects it as a global)
336+
// This is generic - any bundle that exports WebView will have it extracted to global scope
337+
footer += `\nif (typeof ${exportedFileVarName} !== 'undefined' && ${exportedFileVarName}.WebView) { typeof(globalThis) == "undefined" ? (this.WebView = ${exportedFileVarName}.WebView) : (globalThis.WebView = ${exportedFileVarName}.WebView); }`
281338

282339
// Extract React and ReactDOM to global scope from Root bundle
283340
// Root bundle now includes React and ReactDOM, and other bundles (like Forms) need them as globals

0 commit comments

Comments
 (0)