From e3f621ad81ba964864906dadf1aec039ee87874a Mon Sep 17 00:00:00 2001 From: Paul Derscheid 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. --- .../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 d5ac78f8da..a926f82db8 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 @@ +
+ + +
+ [% 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 %] + [% 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 0000000000..3598646303 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Islands/DialogIsland.vue @@ -0,0 +1,107 @@ + + + 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 c5e04a183a..9a96915af8 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 = 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 = 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 01465cc125..351e60d2d6 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.46.1