Skip to content

feat: script and style support in the ui-template code editor - #2291

Open
Steve-Mcl wants to merge 1 commit into
feat/ui-template-vue-scriptfrom
feat/ui-template-script-style
Open

Steve-Mcl wants to merge 1 commit into
feat/ui-template-vue-scriptfrom
feat/ui-template-script-style

Conversation

@Steve-Mcl

Copy link
Copy Markdown
Contributor

Description

Builds on #2290 and node-red/node-red#5994. Related to node-red/nr-monaco-build#9 and node-red/nr-monaco-build#18.

Summary

#2290 gives ui-template Vue and Vuetify editing.

Inside <script> and <style> it only highlights code. node-red/node-red#5994 adds JavaScript and CSS support for those blocks to Node-RED's HTML editors, and an API (RED.editor.codeEditor.monaco.registerEmbeddedLanguages) so other HTML-like languages can opt in.

This PR opts ui-template's vue-sfc language in, and adds the parts that are specific to Dashboard: the type of this.

With a Node-RED version that includes node-red/node-red#5994, the ui-template editor gets:

  • <script>: JavaScript completion, hover info, parameter hints, go to definition and error checking. this knows the component: data, computed and methods, plus what Dashboard adds: this.send(), this.submit(), this.msg, this.value, this.id, this.props, this.$socket, this.$store, this.$router, this.$vuetify and the usual Vue instance members.
  • <style>: CSS checking. With feat: expose the CSS and HTML language workers node-red/nr-monaco-build#18 in Node-RED's Monaco, also CSS completion, hover and colour previews.

On older Node-RED nothing changes: ui-template keeps the Vue/Vuetify support from #2290, and this code isn't even loaded.

How it works

Node-RED does the heavy lifting: a hidden copy of each block that Monaco's TypeScript and CSS workers answer for, mapped back onto the editor. Dashboard only tells it how to read a ui-template script, matching how Dashboard runs it (ui/src/widgets/ui-template/UITemplate.vue, ui/src/util/vue.acorn.js):

  • A component script (the only statement is export default { ... }) is rewritten in the hidden copy as export default __uiTemplate({ ... }). A small type declaration then gives this the right type in data, computed, methods, watch, mounted and unmounted.
  • Any other script runs inside mounted, so it's wrapped in a function whose this is the component.

Files:

  • resources/vue-editor/vue-script.mjs (new, ~145 lines): the this type declarations, the wrapper, and the call to registerEmbeddedLanguages. The wrapper's helper names are hidden from completions, and $ members sort after the component's own.
  • resources/vue-editor/vue-sfc.mjs: loads vue-script.mjs only when Node-RED provides registerEmbeddedLanguages.
  • nodes/plugins/vue-editor.html: uses Node-RED's registerHTMLLanguage when present, which also maps the language to the html worker. Older Node-RED keeps feat: Vue and Vuetify editing in the ui-template code editor #2290's own registration and worker mapping.
  • docs/en/nodes/widgets/ui-template.md: one more bullet in the Code Editor section.

TypeScript details I hit, recorded in the type declarations:

  • One unsupported option (e.g. created, which Dashboard ignores with a console warning) made TypeScript give up and type this as any. So the options type allows other keys and doesn't warn about them.
  • Typing this directly on watch / mounted / unmounted broke inference when watch comes before methods. They take this from the surrounding ThisType, like Vue's own types.

Testing

  • New unit tests in test/resources/vue-script.spec.js (8): component vs raw detection matching Dashboard's parser, the wrapper's insertions, the type declarations, and activate() with and without Node-RED's API. The full suite passes (255) and lint is clean.
  • Checked the types with the TypeScript 5.9 language service, using Node-RED's hidden-document code plus this wrapper. this. in a component lists count, doubled, go, id, items, msg, other, props, send, submit, value..., and this.count is number. Leaving out each option in turn (data/computed/watch/methods/mounted) keeps the typing.
  • Checked in the browser with Playwright, against Node-RED with feat: add JavaScript and CSS support to script and style blocks in HT… node-red/node-red#5994:
    • this. lists the component's own members first, then Dashboard's;
    • this.send( shows its signature and description;
    • notDefined() is underlined on the right line;
    • raw scripts get the same this;
    • with feat: expose the CSS and HTML language workers node-red/nr-monaco-build#18: CSS completion and colour swatches in <style>;
    • no console errors;
    • nothing left behind after closing the editor.
  • Node-RED 4.1.13 with this branch: vue-script.mjs isn't requested, feat: Vue and Vuetify editing in the ui-template code editor #2290's Vue/Vuetify support works as before, no console errors.

Related Issue(s)

#2290
node-red/node-red#5994
node-red/nr-monaco-build#9
node-red/nr-monaco-build#18

Checklist

  • I have read the contribution guidelines
  • Suitable unit/system level tests have been added and they pass
  • Documentation has been updated
    • Upgrade instructions
    • Configuration details
    • Concepts
  • Changes flowforge.yml?
    • Issue/PR raised on FlowFuse/helm to update ConfigMap Template
    • Issue/PR raised on FlowFuse/CloudProject to update values for Staging/Production
  • Link to Changelog Entry PR, or note why one is not needed.

Labels

  • Includes a DB migration? -> add the area:migration label

Builds on node-red/node-red#5994, which adds JavaScript and CSS support to <script>
and <style> blocks in Node-RED's HTML editors and lets other HTML-like languages opt
in. This opts the ui-template's vue-sfc language in and adds what is specific to
Dashboard: the type of `this`.

- Component scripts (a single `export default { ... }`) are wrapped in the hidden
  copy so `this` in data, computed, methods, watch, mounted and unmounted knows the
  component's members and what Dashboard adds (send, submit, msg, value, id, props,
  $socket, $store, $router, $vuetify, ...)
- Other scripts, which Dashboard runs inside mounted, get the same `this`
- Only loaded when Node-RED provides registerEmbeddedLanguages, so older Node-RED
  is unaffected
- The plugin uses Node-RED's registerHTMLLanguage when present, which also maps
  the worker, instead of its own registration and worker shim
@Steve-Mcl

Copy link
Copy Markdown
Contributor Author

Demo:

chrome_RIkP8VNgbM

@Steve-Mcl

Copy link
Copy Markdown
Contributor Author

better demo:

ui-template-vue-vuetify-demo.mp4

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant