0
votes

I am making an embeddable Vue widget via @vue/cli. Goal is to have user place a snippet into their website:

<script src="https://test.com/embed.unique.js"></script>

This script creates the root element (<div id="app"></div>) and injects (node.insertBefore()) the app bundle after the root element.

This works great on localhost, but does not work when serving from live server. If I place the bundle script tag directly in the HTML it works on live server as well, but again not when injected.

After debugging, it appears the main Vue webpack module never executes (Vue itself is included in the bundle as well).

package.json

{
    "name": "test",
    "version": "0.1.0",
    "private": true,
    "scripts": {
      "serve": "vue-cli-service serve",
      "build": "vue-cli-service build",
      "lint": "vue-cli-service lint",
    },
    "dependencies": {
      "core-js": "^3.6.5",
      "vue": "^2.6.11"
    },
    "devDependencies": {
      "@vue/cli-plugin-babel": "~4.4.6",
      "@vue/cli-plugin-eslint": "~4.4.6",
      "@vue/cli-service": "~4.4.6",
      "@vue/eslint-config-airbnb": "^5.1.0",
      "babel-eslint": "^10.1.0",
      "eslint": "^7.6.0",
      "eslint-plugin-import": "^2.22.0",
      "eslint-plugin-vue": "^6.2.2",
      "sass": "^1.26.10",
      "sass-loader": "^9.0.3",
      "vue-template-compiler": "^2.6.11",
    }
  }

vue.config.js

module.exports = {
    publicPath: (process.env.NODE_ENV === 'production') ? 'https://test.com/' : '/',
    filenameHashing: false,
    css: {
        extract: false,
    },
    chainWebpack(config) {
        config.optimization.delete('splitChunks')
        config.plugins.delete('prefetch')
    },
}

src/main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
    render: (h) => h(App),
}).$mount('#app')

embed.unique.js

;(function(d,c,k,a,h,s){
c=d.currentScript||d.querySelector('script[src$="embed.unique.js"]')
k=d.createElement('div')
k.id='app'
c.parentNode.insertBefore(k,c)
a=d.createElement('a')
a.href=c.src
h=a.href.replace(a.pathname,'')
s=d.createElement('script')
s.src=h+'/js/app.js'
c.parentNode.insertBefore(s,c)
})(document);
1

1 Answers

0
votes

So I figured it out. This embed worked fine on other websites, but had issues on websites that also used a webpack bundle. The fix for me was to set a different jsonpFunction value in the webpack config.

vue.config.js

module.exports = {
    publicPath: (process.env.NODE_ENV === 'production') ? 'https://test.com/' : '/',
    filenameHashing: false,
    css: {
        extract: false,
    },
    chainWebpack(config) {
        config.optimization.delete('splitChunks')
        config.plugins.delete('prefetch')
        config.output.set('jsonpFunction', 'customWebpackJsonp')
    },
}