Bugzilla – Attachment 172974 Details for
Bug 37911
Prototype vue islands within static pages
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 37911: (follow-up) Allow for initialisation of islands on demand
Bug-37911-follow-up-Allow-for-initialisation-of-is.patch (text/plain), 16.90 KB, created by
Matt Blenkinsop
on 2024-10-18 12:07:31 UTC
(
hide
)
Description:
Bug 37911: (follow-up) Allow for initialisation of islands on demand
Filename:
MIME Type:
Creator:
Matt Blenkinsop
Created:
2024-10-18 12:07:31 UTC
Size:
16.90 KB
patch
obsolete
>From 65bd74127d5d665f624e7503b5b7d8a039edc33d Mon Sep 17 00:00:00 2001 >From: Paul Derscheid <paul.derscheid@lmscloud.de> >Date: Wed, 18 Sep 2024 17:00:13 +0000 >Subject: [PATCH] Bug 37911: (follow-up) Allow for initialisation of islands on > demand > >- Split the rspack config into a umd and an esm section. >- Don't hydrate by default. > - Instead check the "init" attribute for the currentScript when using the umd. > - Allow for manual import and call when using the esm. > - Add examples for both in intranet-main.tt (to be removed). >- Add a DialogIsland wrapper for the shared Dialog component (to map props to stored refs). >- Move DialogIsland as well as Demo components into an Islands directory under components. >- Add i18n initialisation to hydrate's idle callback. > >Signed-off-by: Matt Blenkinsop <matt.blenkinsop@ptfs-europe.com> >--- > .../prog/en/modules/intranet-main.tt | 20 +- > .../vue/components/Islands/DialogIsland.vue | 107 +++++++++ > .../components/{ => Islands}/HelloIslands.vue | 0 > .../components/{ => Islands}/HelloWorld.vue | 0 > .../prog/js/vue/modules/islands.ts | 25 +- > rspack.config.js | 216 +++++++++++------- > 6 files changed, 284 insertions(+), 84 deletions(-) > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/DialogIsland.vue > rename koha-tmpl/intranet-tmpl/prog/js/vue/components/{ => Islands}/HelloIslands.vue (100%) > rename koha-tmpl/intranet-tmpl/prog/js/vue/components/{ => Islands}/HelloWorld.vue (100%) > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >index 378cff5a553..9d1b6592799 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >@@ -315,8 +315,22 @@ > <!-- <hello-world></hello-world> --> > </div> <!-- /.row --> > >+ <div class="row w-25 m-auto p-4 border border-4 border-warning br-5 rounded text-center mt-4"> >+ <dialog-island id="surprise"></dialog-island> >+ <button id="surprise-button" class="btn btn-primary">Click me for a surprise!</button> >+ </div> >+ > [% MACRO jsinclude BLOCK %] >- [% Asset.js("js/vue/dist/islands.js", "type" => "module") | $raw %] >+ [% INCLUDE 'calendar.inc' %] >+ [% Asset.js("js/vue/dist/islands.js", "init" => "1") | $raw %] >+ <!-- >+ [% SET islands = Asset.js("js/vue/dist/islands.esm.js").match('(src="([^"]+)")').1 %] >+ <script src="[% islands %]" type="module"></script> >+ <script type="module"> >+ import { hydrate } from "[% islands %]"; >+ hydrate(); >+ </script> >+ --> > <script> > var MSG_CONFIRM_DELETE = _("Are you sure you want to delete this news item? This cannot be undone."); > $(document).ready(function(){ >@@ -328,6 +342,10 @@ > const [firstHelloIslandsElement] = document.getElementsByTagName("hello-islands"); > firstHelloIslandsElement.message = 'This is a delayed update to the message attribute of the web commponent.' > }, 2000); >+ >+ $("#surprise-button").on("click", () => { >+ $("#surprise").attr("warning", `<span>Yes, this is <span class="font-monospace">Dialog.vue</span> (in a wrapper component)!</span><span class="d-none">${Math.random()}</span>`); >+ }); > }); > </script> > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/DialogIsland.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/DialogIsland.vue >new file mode 100644 >index 00000000000..35986463037 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/DialogIsland.vue >@@ -0,0 +1,107 @@ >+<template> >+ <Dialog /> >+</template> >+ >+<script> >+import { inject, watch } from "vue" >+import Dialog from "../Dialog.vue" >+ >+export default { >+ props: { >+ message: { >+ type: String, >+ default: null, >+ }, >+ error: { >+ type: String, >+ default: null, >+ }, >+ warning: { >+ type: String, >+ default: null, >+ }, >+ confirmation: { >+ type: Object, >+ default: () => null, >+ }, >+ isSubmitting: { >+ type: Boolean, >+ default: false, >+ }, >+ isLoading: { >+ type: Boolean, >+ default: false, >+ }, >+ acceptCallback: { >+ type: Function, >+ default: null, >+ }, >+ }, >+ setup(props) { >+ const mainStore = inject("mainStore") >+ const { >+ setMessage, >+ setError, >+ setWarning, >+ setConfirmation, >+ setSubmitting, >+ setLoading, >+ setAcceptCallback, >+ } = mainStore >+ >+ watch( >+ () => props.message, >+ newVal => { >+ setMessage(newVal) >+ } >+ ) >+ >+ watch( >+ () => props.error, >+ newVal => { >+ setError(newVal) >+ } >+ ) >+ >+ watch( >+ () => props.warning, >+ newVal => { >+ setWarning(newVal) >+ } >+ ) >+ >+ watch( >+ () => props.confirmation, >+ newVal => { >+ setConfirmation(newVal) >+ } >+ ) >+ >+ watch( >+ () => props.isSubmitting, >+ newVal => { >+ setSubmitting(newVal) >+ } >+ ) >+ >+ watch( >+ () => props.isLoading, >+ newVal => { >+ setLoading(newVal) >+ } >+ ) >+ >+ watch( >+ () => props.acceptCallback, >+ newVal => { >+ setAcceptCallback(newVal) >+ } >+ ) >+ >+ return {} >+ }, >+ components: { >+ Dialog, >+ }, >+} >+</script> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/HelloIslands.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/HelloIslands.vue >similarity index 100% >rename from koha-tmpl/intranet-tmpl/prog/js/vue/components/HelloIslands.vue >rename to koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/HelloIslands.vue >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/HelloWorld.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/HelloWorld.vue >similarity index 100% >rename from koha-tmpl/intranet-tmpl/prog/js/vue/components/HelloWorld.vue >rename to koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/HelloWorld.vue >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts >index c5e04a183a9..9a96915af84 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts >@@ -1,5 +1,6 @@ > import { Component, defineCustomElement } from "vue"; > import { createPinia } from "pinia"; >+import { $__ } from "../i18n"; > import { useMainStore } from "../stores/main"; > import { useNavigationStore } from "../stores/navigation"; > >@@ -27,7 +28,7 @@ export const componentRegistry: Map<string, WebComponentDynamicImport> = > importFn: async () => { > const module = await import( > /* webpackChunkName: "hello-islands" */ >- "../components/HelloIslands.vue" >+ "../components/Islands/HelloIslands.vue" > ); > return module.default; > }, >@@ -42,12 +43,27 @@ export const componentRegistry: Map<string, WebComponentDynamicImport> = > importFn: async () => { > const module = await import( > /* webpackChunkName: "hello-world" */ >- "../components/HelloWorld.vue" >+ "../components/Islands/HelloWorld.vue" > ); > return module.default; > }, > }, > ], >+ [ >+ "dialog-island", >+ { >+ importFn: async () => { >+ const module = await import( >+ /* webpackChunkName: "vue-dialog" */ >+ "../components/Islands/DialogIsland.vue" >+ ); >+ return module.default; >+ }, >+ config: { >+ stores: ["mainStore"], >+ }, >+ }, >+ ], > ]); > > /** >@@ -88,6 +104,7 @@ export function hydrate(): void { > app.provide(store, storesMatrix[store]); > }); > } >+ app.config.globalProperties.$__ = $__; > // Further config options can be added here as we expand this further > }, > }), >@@ -97,4 +114,6 @@ export function hydrate(): void { > }); > } > >-hydrate(); >+if (parseInt(document?.currentScript?.getAttribute("init") ?? "0", 10)) { >+ hydrate(); >+} >diff --git a/rspack.config.js b/rspack.config.js >index 01465cc1253..351e60d2d64 100644 >--- a/rspack.config.js >+++ b/rspack.config.js >@@ -3,92 +3,148 @@ const { VueLoaderPlugin } = require("vue-loader"); > const path = require("path"); > const rspack = require("@rspack/core"); > >-module.exports = { >- experiments: { >- css: true, >- }, >- entry: { >- erm: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/erm.ts", >- preservation: >- "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts", >- "admin/record_sources": >- "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts", >- islands: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts", >- }, >- output: { >- filename: "[name].js", >- path: path.resolve( >- __dirname, >- "koha-tmpl/intranet-tmpl/prog/js/vue/dist/" >- ), >- chunkFilename: "[name].[contenthash].js", >- globalObject: "window", >- }, >- module: { >- rules: [ >- { >- test: /\.vue$/, >- loader: "vue-loader", >- options: { >- experimentalInlineMatchResource: true, >+module.exports = [ >+ { >+ experiments: { >+ css: true, >+ }, >+ entry: { >+ erm: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/erm.ts", >+ preservation: >+ "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts", >+ "admin/record_sources": >+ "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/admin/record_sources.ts", >+ islands: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts", >+ }, >+ output: { >+ filename: "[name].js", >+ path: path.resolve( >+ __dirname, >+ "koha-tmpl/intranet-tmpl/prog/js/vue/dist/" >+ ), >+ chunkFilename: "[name].[contenthash].js", >+ globalObject: "window", >+ }, >+ module: { >+ rules: [ >+ { >+ test: /\.vue$/, >+ loader: "vue-loader", >+ options: { >+ experimentalInlineMatchResource: true, >+ }, >+ exclude: [path.resolve(__dirname, "t/cypress/")], > }, >- exclude: [path.resolve(__dirname, "t/cypress/")], >- }, >- { >- test: /\.ts$/, >- loader: "builtin:swc-loader", >- options: { >- jsc: { >- parser: { >- syntax: "typescript", >+ { >+ test: /\.ts$/, >+ loader: "builtin:swc-loader", >+ options: { >+ jsc: { >+ parser: { >+ syntax: "typescript", >+ }, > }, >+ appendTsSuffixTo: [/\.vue$/], > }, >- appendTsSuffixTo: [/\.vue$/], >+ exclude: [ >+ /node_modules/, >+ path.resolve(__dirname, "t/cypress/"), >+ ], >+ type: "javascript/auto", > }, >- exclude: [ >- /node_modules/, >- path.resolve(__dirname, "t/cypress/"), >- ], >- type: "javascript/auto", >- }, >- { >- test: /\.css$/i, >- type: "javascript/auto", >- use: ["style-loader", "css-loader"], >- }, >+ { >+ test: /\.css$/i, >+ type: "javascript/auto", >+ use: ["style-loader", "css-loader"], >+ }, >+ ], >+ }, >+ plugins: [ >+ new VueLoaderPlugin(), >+ new rspack.DefinePlugin({ >+ __VUE_OPTIONS_API__: true, >+ __VUE_PROD_DEVTOOLS__: false, >+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false, >+ }), > ], >+ externals: { >+ jquery: "jQuery", >+ "datatables.net": "DataTable", >+ "datatables.net-buttons": "DataTable", >+ "datatables.net-buttons/js/buttons.html5": "DataTable", >+ "datatables.net-buttons/js/buttons.print": "DataTable", >+ "datatables.net-buttons/js/buttons.colVis": "DataTable", >+ }, > }, >- /** >- optimization: { >- splitChunks: { >- chunks: "all", >- cacheGroups: { >- default: false, // Disable default cache groups to avoid affecting existing bundles >- vendors: false, // Disable vendor caching >- vue: { >- test: /[\\/]node_modules[\\/]vue[\\/]/, >- name: "vue", >- chunks: "all", >- enforce: true, >- }, >+ { >+ experiments: { >+ css: true, >+ outputModule: true, >+ }, >+ entry: { >+ islands: "./koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts", >+ }, >+ output: { >+ filename: "[name].esm.js", >+ path: path.resolve( >+ __dirname, >+ "koha-tmpl/intranet-tmpl/prog/js/vue/dist/" >+ ), >+ chunkFilename: "[name].[contenthash].esm.js", >+ globalObject: "window", >+ library: { >+ type: "module", > }, > }, >+ module: { >+ rules: [ >+ { >+ test: /\.vue$/, >+ loader: "vue-loader", >+ options: { >+ experimentalInlineMatchResource: true, >+ }, >+ exclude: [path.resolve(__dirname, "t/cypress/")], >+ }, >+ { >+ test: /\.ts$/, >+ loader: "builtin:swc-loader", >+ options: { >+ jsc: { >+ parser: { >+ syntax: "typescript", >+ }, >+ }, >+ appendTsSuffixTo: [/\.vue$/], >+ }, >+ exclude: [ >+ /node_modules/, >+ path.resolve(__dirname, "t/cypress/"), >+ ], >+ type: "javascript/auto", >+ }, >+ { >+ test: /\.css$/i, >+ type: "javascript/auto", >+ use: ["style-loader", "css-loader"], >+ }, >+ ], >+ }, >+ plugins: [ >+ new VueLoaderPlugin(), >+ new rspack.DefinePlugin({ >+ __VUE_OPTIONS_API__: true, >+ __VUE_PROD_DEVTOOLS__: false, >+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false, >+ }), >+ ], >+ externals: { >+ jquery: "jQuery", >+ "datatables.net": "DataTable", >+ "datatables.net-buttons": "DataTable", >+ "datatables.net-buttons/js/buttons.html5": "DataTable", >+ "datatables.net-buttons/js/buttons.print": "DataTable", >+ "datatables.net-buttons/js/buttons.colVis": "DataTable", >+ }, > }, >- */ >- plugins: [ >- new VueLoaderPlugin(), >- new rspack.DefinePlugin({ >- __VUE_OPTIONS_API__: true, >- __VUE_PROD_DEVTOOLS__: false, >- __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false, >- }), >- ], >- externals: { >- jquery: "jQuery", >- "datatables.net": "DataTable", >- "datatables.net-buttons": "DataTable", >- "datatables.net-buttons/js/buttons.html5": "DataTable", >- "datatables.net-buttons/js/buttons.print": "DataTable", >- "datatables.net-buttons/js/buttons.colVis": "DataTable", >- }, >-}; >+]; >-- >2.39.3 (Apple Git-146)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 37911
:
171425
|
171426
|
171432
|
171439
|
171440
|
171445
|
171459
|
171517
|
171538
|
171608
|
171685
|
172962
|
172963
|
172965
|
172966
|
172967
|
172968
|
172969
|
172970
|
172971
|
172972
|
172973
| 172974 |
172975