Here are few thoughts from my end on this topic, but in a non-wp context. There might be other solutions too.
Generally assets (js/css) files are cached, so ādownloadingā twice is not really a concern, as the second call to the asset will generally be picked from the cache. So, loading two js files of 100kb doesnāt always end up ādownloadingā 200kb (of course, there are always exceptional scenarios, but they are uncommon). Same applies to css files too. To beat this caching is why build tools like webpack, vite add a āhashā to these assets.
The real concern is the āre-executionā of the second redundant script tag, unless the script is protected against double-inclusion. For eg, jQuery doesnāt, function foo(){} in the script file will be executed twice, and might attach duplicate event listeners. The same concern for css, as the second style tag, will end up overriding the first one. So, avoiding double inclusion of js/lib files must be avoid for this reason, not necessary to save data download.
What you are attempting to do with two blocks is similar to the concepts of āislandsā, lately popularised by js frameworks like Astro & Iles. These modern frameworks use module scripts (type=āmoduleā) instead of the traditional classic scripts.
Module scripts are different to classic scripts:
- Singleton (loaded only once, even if imported multiple times)
- Deferred by default (executed after HTML content is parsed, so can be used anywhere within the document. Nice to co-locate them with itās content.
- Strict mode - all objects (let, const, var, function, class) are private unless explicitly exported.
- Uses modern ES module syntax, can be broken down into smaller chunks and import/export nicely. No file protocol, so external module imports (src=ā./my-module.jsā) wonāt work if the page is opened directly in the browser, without a live-server.
For eg, if you add the below two islands to two blocks, and check your network tab in your browser, you will notice that the petite-vue will be downloaded & executed only once (singleton). Not sure if uikit provides a module script via cdn.
So, for javascript, you could use module scripts (type=āmoduleā), but I believe when using it with WP, you probably have to āDo not enqueueā it as currently Pinegrow WP builder doesnāt differentiate module vs classic scripts and ignores the type (type=āmoduleā) when exporting theme/plugin.
With regards to how to avoid double css download & execution (cascading) in the WP block context, Iām not sure about it, lets wait to hear more from the community on this topic. Obviously, double download of css import could be avoided by using javascript, but thatās not very clean. And Iām not very familiar with WP blocks world, so I better donāt say anything inaccurate.
Island-1:
<script type="module" data-pg-name="Pt-App-Hero" id="hero-app">
import { createApp } from 'https://unpkg.com/petite-vue?module'
const state = {
// state exposed to all expressions within v-scope regions
count: 0,
get oddOrEven() {
return this.count % 2 === 0 ? 'even' : 'odd' // computed property
},
// methods
increment() {
this.count++
},
decrement() {
this.count--
},
}
createApp(state).mount('div#hero-island')
</script>
<div
id="hero-island"
data-pg-name="Pt-Island-Hero"
v-scope="{}"
style="
padding: 20px;
margin: 20px;
border-radius: 4px;
border-width: 2px;
outline: 1px solid #cccccc;
"
data-pg-collapsed
>
<div
style="
display: flex;
margin: 8px;
padding: 8px;
justify-content: center;
align-items: center;
"
>
<p style="text-align: center; width: 50%; min-width: 400px">
Hello, I'm within an island, and the root tag of the island
<code>div#hero-island</code> has an exclusive app mounted by
<code>script#hero-app</code>, and marked as a
<code>v-scope</code> region. Any sprinkles of interactions within this
<code>v-scope</code> region are managed by this exclusive app.
</p>
</div>
<div
style="
display: flex;
margin: 8px;
padding: 8px;
justify-content: center;
align-items: center;
"
>
<button
v-on:click="decrement"
style="margin-left: 4px; margin-right: 4px"
>
ā¬ļø
</button>
<button
v-on:click="increment"
style="margin-left: 4px; margin-right: 4px"
>
ā¬ļø
</button>
<div v-cloak style="text-align: left; width: 180px; margin-left: 4px">
<span>Count is: </span>
<span style="width: 30px; display: inline-block; text-align: center"
>{{count}}</span
><span v-cloak>({{oddOrEven}})</span>
</div>
</div>
</div>
Island-2:
<script type="module" data-pg-name="Pt-App-Feature" id="feature-app">
import { createApp } from 'https://unpkg.com/petite-vue?module'
const state = {
// state exposed to all expressions within v-scope regions
msg: 'Happy Life!',
}
createApp(state).mount('div#feature-island')
</script>
<div
id="feature-island"
data-pg-name="Pt-Island-Feature"
v-scope="{}"
style="
padding: 20px;
margin: 20px;
border-radius: 4px;
border-width: 2px;
outline: 1px solid #cccccc;
"
>
<div
style="
display: flex;
margin: 8px;
padding: 8px;
justify-content: center;
align-items: center;
"
>
<p style="text-align: center; width: 50%; min-width: 400px">
Hello, I'm within an island, and the root tag of the island
<code>div#feature-island</code> has an exclusive app mounted by
<code>script#feature-app</code>, and marked as a
<code>v-scope</code> region. Any sprinkles of interactions within this
<code>v-scope</code> region are managed by this exclusive app.
</p>
</div>
<div
style="
display: flex;
margin: 8px;
padding: 8px;
justify-content: center;
align-items: center;
flex-direction: column;
"
>
<input v-model="msg" style="text-align: center" /><span
v-cloak
style="margin: 8px"
>{{msg}}</span
>
</div>
</div>