Using VueJS 3 ES Module without a build step

Some hopefully helpful notes for using Vue JS 3 without a build step — that is, using the browser build. If you’re reading this from the future, keep in mind that this represents my understanding as of time of writing, and using Vue JS 3.3.4. Things may have changed for the better (or worse).

It goes without saying that you would need the vue javascript from CDN. Whether you choose the Global build or the ESM module is probably down to you, but it may be worth choosing the ES Module version if you expect to use many other libraries and want to reduce noise in the global space. The documentation mostly uses ES Module syntax, so that is another good reason to go with the ES build.

Import Maps

You will need to create import maps, as this makes using vue and other libraries and components easier. Libraries I have come across, like datatables.net-vue assume that there is an import map, and when you use one component from the library which itself uses another component, they expect an import map exists to find the relevant JS for the components they referenced.

As far as I know for the moment, you need to manually curate your import map and update it as you add libraries. Here is an example import map with vue JS and datatables.net

<script type="importmap">
    {
        "imports": {
            "vue": "{url_prefix_to_vue}/vue.esm-browser.prod.js",
            "datatables.net-vue3": "{url_prefix_to_datatables_VUE_build}datatables.net-vue3.mjs",
            "datatables.net-buttons": "{url_prefix_to_datatables}/Buttons-2.4.2/js/dataTables.buttons.min.mjs",
            "datatables.net-buttons-bs5": "{url_prefix_to_datatables}/Buttons-2.4.2/js/buttons.bootstrap5.min.mjs",
            "datatables.net-buttons-html5": "{url_prefix_to_datatables}/Buttons-2.4.2/js/buttons.html5.min.mjs",
            "datatables.net-bs5": "{{url_prefix_to_datatables}/dataTables.bootstrap5.min.mjs",
            "datatables.net": "{url_prefix_to_datatables}/jquery.dataTables.min.mjs",
            "datatables.net-jszip": "{url_prefix_to_datatables}/JSZip-3.10.1/jszip.min.js",
            "datatables.net-responsive": "{url_prefix_to_datatables}/Responsive-2.5.0/js/dataTables.responsive.min.mjs",
            "datatables.net-responsive-bs5": "{url_prefix_to_datatables}/Responsive-2.5.0/js/responsive.bootstrap5.min.mjs",
            "jquery": "{url_prefix_to_jquery_es_build}/.esm-shim.js"

        }
    }
</script>

Datatables still relies on Jquery, so you need an ES build of jquery. The files themselves don’t have to be served from a CDN, they can be served from your own domain. Keep in mind the necessity of Cross-Origin-Resource Sharing if the JS files are from an alternate domain.

Template syntax

Kebab Case only

When developing and using components, you have to use kebab-case to refer to your components, as opposed to the Pascal case that is commonly used in the documentation. For example, to create a DataTable from above, you would write the tag as <data-table> NOT <DataTable>.

Similar treatment is required for event handling.

Short Tags

Avoid the use of short style tags. Example <data-table … />. I found that the in-browser compiler doesn’t handle these well. If you’re experiencing issues like missing markup in your browser when you inspect the rendered page, then you likely have used a component and closed it with the short style. Always close your tags fully <data-table …> … </data-table>.

Find Native Libraries

If you’re starting out a new project or re-writing an old project based on say bootstrap, jquery, and a collection of jquery plugins for more advanced UI interactions, it is comforting to read that you could drop vue JS in and slowly work your way through the conversion. Indeed, it is relatively easy to start using vue JS quickly in a legacy project, but there is very little support available. The documentation is largely written on the assumption that you’re using a build step and you have a magical development environment where you just write a bunch of Single-File Components, link them up, push a button, some magic happens, and you have a nicely written vue front end deployed for you.

If you’re reading this article, then you probably know that legacy codebases aren’t always like this. If you’re translating or rewriting an old app, don’t just assume you should get the latest versions of your existing libraries, stick Vue JS in and continue to evolve. You should pause and look at the Vue JS landscape and find native libraries that meet your requirements, and adopt those instead.

For example, in place of bootstrap and datatables.net, you could look into PrimeFlex and PrimeVue which combined provide you with probably all the layout and theming and advanced html components you may need in a modern application. These two libraries on their own probably remove the need for any other external dependencies.

Bear in mind, that your import map is being curated manually, and will need to grow to accomodate PrimeVue if you choose to adopt it. You may want to search for, or create a script to generate import maps. If you find or create one, please drop a comment, this could be a genuinely useful tool. Bonus points if the tool you create doesn’t depend on nodeJS (I have no beef with it, it’s just one fewer ecosystem to worry about security vulnerabilities).

A single python, php, rust, or go binary that could generate import maps would be a lot easier sell than a node JS package for integrating into a dev-ops environment that doesn’t otherwise have other node JS dependencies. I am open to be schooled on this.

Food for thought

It’s unclear to me the cost of having in-browser compilation of a vue JS app when using the CDN approach without a build step. Modern computers are fast, and modern browsers have fast javascript interpreters, so performance has not been a concern for the kinds of projects I have played with.