Tutorial
LiveView and page specific javascript
In most applications you have some page specific javascript that is only used in one or just a few pages. The solution for this is to either setup your javascript build system to output several bundles that you can include on the pages you want or import the script files from the CDN sources on the pages you want and then use them in your code.
In this tutorial, I want to show how I use option two, import the javascript from external CDN:s and use that in conjunction with Phoenix LiveView to avoid having the user to download a larger javascript bundle that is not needed on most pages. This is a pattern that I have started to follow recently and that I feel good about.
On my new site, https://livesaaskit.com/ I use this in a couple of places. The first example is when a user wants to copy a snippet of code.
On the top right in the code box, there is an icon that when you click on it, it copies the entire code snippet. For this I use the library https://github.com/feross/clipboard-copy which is available as a NPM package but I prefer to keep my bundle as small as possible.
This works by adding an event listener to the click event on the copy button. Since my entire site is a LiveView site, I want to set this up by using a LiveView hook.
Since I don’t want to add the library to my javascript bundle, I need to import it from an external source. One of the sources I like to use is Skypack. https://www.skypack.dev/view/clipboard-copy
The example says I can use it like:
<script type="module">
import clipboardCopy from 'https://cdn.skypack.dev/clipboard-copy';
</script>
So, in the bottom of my root layout file, I use it like:
<!-- lib/live_saas_kit_web/templates/layout/root.html.heex -->
<script type="module">
import clipboardCopy from 'https://cdn.skypack.dev/clipboard-copy'
window.clipboardCopy = clipboardCopy
</script>
Note that I attach it directly to the window, which you probably should be a little careful about to avoid name collisions.
Since I want to use this is a Phoenix LiveView hook, I need to add the hook on the button and I name it CodeCopy
<!-- show.html.heex -->
<button phx-hook="CodeCopy" id="copy-button-1" type="button" title="Copy Code" class="btn copy-block-btn btn-circle text-opacity-30 hover:text-opacity-70">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
</button>
Then I define the hook in javascript like this. Note that I add an event listener to the button and listens for a click. And when someone clicks the button, I copy the content of the codeblock.
// assets/js/code_copy.js
export const CodeCopy = {
mounted() {
const elm = this.el const btn = elm.querySelector('.copy-block-btn')
const content = elm.querySelector('code') && elm.querySelector('code').innerText if (btn && content) {
btn.addEventListener('click', () => {
clipboardCopy(content)
})
}
},
}
Note that clipboardCopy
are available from window object through the Skypack import.
I have come to like this approach since I can keep the javascript bundle as small as possible and I can even avoid using any kind of javascript processing.