Nuxt mounts tripartite JS script plug-ins

The cause of

Because of the company’s official website function migration, from the original SPA application to the SSR application of Nuxt, involved in the loading of third-party customer service scripts, the front-end is not familiar with the artist to help, so I wrote a Vue plug-in to save colleagues in the fire.

TODO List

  • Mount tripartite JS scripts
  • Uninstall the tripartite JS script
  • Provide global methods
  • Initializes the incoming configuration item
  • Use to register plug-ins with vue.use

Mount the script

const PluginName = 'LoadScriptPlugin'

const prefix = `[${PluginName}] - `



/** @typedef {{name: string, src: string, selector? : string, defer? : boolean, async? : boolean}} ScriptOption */



/ * *

* Create and mount scripts

* @param {ScriptOption} option Mount script options

 * @returns {void}

* /

function createScript(option = {}) {

  if(typeof option ! = ='object' || option === null) {

    option = {}

  }



  const scriptId = `${prefix}${name}`

  const script = document.createElement('script')

  const parentEl = document.querySelector(selector) || document.body



  script.id = scriptId

  script.src = option.src

  script.defer = option.defer

  script.async = option.async

  

  parentEl.append(script)

}

Copy the code

The above code creates the script tag with createElement and mounts the script by receiving an external parameter that sets the script’s properties.

To facilitate later unmounting of the script, we also need to record the elements of the script and its elements each time it is mounted. Add the following code:

/ * *

* All script information

 * @description

* parent: parent element

* self: self element (script element)

 *

 * @type {{parent: HTMLElement, self: HTMLElement}}

* /

const scriptMap = {}



function createScript(option = {}) {

// append the tail

  + scriptMap[scriptId] = {

  +  parent: parentEl,

  +  self: script

+}

}

Copy the code

Destruction of the script

We recorded the parent element and its element each time the script was mounted via scriptMap above. Now we destroy the script by creating a function that receives the name identifier.

/ * *

* Destroy scripts

* @param {string} name Specifies the script name

 * @returns {string}

* /

function destroyScript(name) {

  const scriptId = `${prefix}${name}`

  const scriptInfo = scriptMap[scriptId]



  scriptInfo.parent.removeChild(scriptInfo.self)

  delete scriptMap[scriptId]

}

Copy the code

Define the plugin

Above we have implemented the basic functions of the plug-in, but we have not yet seen where the plug-in we defined is. Next we need to visualize the plug-in and expose the installation interface for vue.use.

/ * *

* Vue automatically mounts tripartite script plug-ins

 * @example

 * Vue.use(Plugin, {})

 * // or

 * Vue.use(Plugin, [{}])

* /

const Plugin = {

/ * *

* the plugin name

* /

  name: PluginName,

/ * *

* Installation record

* /

  installed: false.

/ * *

* Installation behavior

   * @param {Vue} Vue

   * @param {ScriptOption|ScriptOption[]|null} options

   * @returns {void}

* /

  install(Vue, options) {

    if (Plugin.installed || Vue.$isServerreturn



    if (options) {

      options = Array.isArray(options) ? options : [options]

      options.forEach((opt) => createScript(opt))

    }

    

    Plugin.installed = true



    Vue.prototype.$createScript = createScript

    Vue.prototype.$destroyScript = destroyScript

  }

}

Copy the code

The above code defines the basic information and installation interface of our plug-in, which can be exported by default and registered with vue. use(LoadScriptPlugin), and can receive options to mount the plug-in at initialization.

Mount our script functions for the Vue prototype to facilitate the dynamic use of mount and destroy script functions in subsequent businesses.

Treatment of boundary

Up to now, our plug-in has basically been implemented, but there are still hidden dangers in use, because we developed it to provide convenience for other personnel to operate, and there may be error in operation when using it without complete understanding, so we need to make strict verification on the receiving parameters.

function log(... messages) {

console.log(prefix, ... messages)

}



functionwarn(... messages) {

console.warn(prefix, ... messages)

}



/ * *

* Create and mount scripts

* @param {ScriptOption} option Mount script options

 * @returns {void}

* /

function createScript(option = {}) {

  if(typeof option ! = ='object' || option === null) {

    option = {}

  }



  if ([' ', null, void 0].includes(option.src)) {

    return warn('The src property of the option cannot be falsly value! ')

  }



  if ([' ', null, void 0].includes(option.name)) {

    return warn(

      'The name property of the option cannot be falsly value! The name property will be used to identify the current script! '

    )

  }



  const scriptId = getScriptId(option.name)



  if (scriptId in scriptMap) {

    return warn('Duplicate name attribute, please re-enter! ')

  }

  

.

  

  log(`The ${name}script been created! `)

}



/ * *

* Destroy scripts

* @param {string} name Specifies the script name

 * @returns {string}

* /

function destroyScript(name) {

.

  

  if(! (scriptIdin scriptMap) || scriptInfo === undefined) {

    return warn(`The script with name as ${name}does not exist! `)

  }



.

  

  log(`The ${name}script been destroyed! `)

}

Copy the code

The complete code

import Vue from 'vue'



const PluginName = 'LoadScriptPlugin'

const prefix = `[${PluginName}] - `



/ * *

* All script information

 * @description

* parent: parent element

* self: self element (script element)

 *

 * @type {{parent: HTMLElement, self: HTMLElement}}

* /

const scriptMap = {}



function log(... messages) {

console.log(prefix, ... messages)

}



functionwarn(... messages) {

console.warn(prefix, ... messages)

}



/ * *

* Gets the parent element to mount

* @param {string} selector

 * @returns {HTMLElement}

* /

function getParentEl(selector) {

  let el = null

  if (selector) el = document.querySelector(selector)

  return el || document.body

}



/ * *

* Gets a unique script identifier

* @param {string} name Specifies the script name

 * @returns {string}

* /

function getScriptId(name) {

  return `${prefix}${name}`

}



/** @typedef {{name: string, src: string, selector? : string, defer? : boolean, async? : boolean}} ScriptOption */



/ * *

* Create and mount scripts

* @param {ScriptOption} option Mount script options

 * @returns {void}

* /

function createScript(option = {}) {

  if(typeof option ! = ='object' || option === null) {

    option = {}

  }



  if ([' ', null, void 0].includes(option.src)) {

    return warn('The src property of the option cannot be falsly value! ')

  }



  if ([' ', null, void 0].includes(option.name)) {

    return warn(

      'The name property of the option cannot be falsly value! The name property will be used to identify the current script! '

    )

  }



  const scriptId = getScriptId(option.name)



  if (scriptId in scriptMap) {

    return warn('Duplicate name attribute, please re-enter! ')

  }



  const script = document.createElement('script')

  const parentEl = getParentEl(option.selector)



  script.id = scriptId

  script.src = option.src

  script.defer = option.defer

  script.async = option.async



  parentEl.append(script)

  scriptMap[scriptId] = {

    parent: parentEl,

    self: script

  }



  log(`The ${name}script been created! `)

}



/ * *

* Destroy scripts

* @param {string} name Specifies the script name

 * @returns {string}

* /

function destroyScript(name) {

  const scriptId = getScriptId(name)

  const scriptInfo = scriptMap[scriptId]



  if(! (scriptIdin scriptMap) || scriptInfo === undefined) {

    return warn(`The script with name as ${name}does not exist! `)

  }



  scriptInfo.parent.removeChild(scriptInfo.self)

  delete scriptMap[scriptId]



  log(`The ${name}script been destroyed! `)

}



/ * *

* Vue automatically mounts tripartite script plug-ins

 * @example

 * Vue.use(Plugin, {})

 * // or

 * Vue.use(Plugin, [{}])

* /

const Plugin = {

/ * *

* the plugin name

* /

  name: PluginName,

/ * *

* Installation record

* /

  installed: false.

/ * *

* Install plugins

   * @param {Vue} Vue

   * @param {ScriptOption|ScriptOption[]|null} options

   * @returns {void}

* /

  install(Vue, options) {

    if (Plugin.installed || Vue.$isServerreturn



    if (options) {

      options = Array.isArray(options) ? options : [options]

      options.forEach((opt) => createScript(opt))

    }



    Plugin.installed = true



    Vue.prototype.$createScript = createScript

    Vue.prototype.$destroyScript = destroyScript

  }

}



// exportDefault Plugin // Export plug-in entry



// Nuxt plugin

Vue.use(Plugin, [

/** Load the customer service script */

  {

    name: 'customService'.

    src: 'xxx

  }

])

Copy the code

The last

The solution of each problem is a step forward for me to achieve wealth and freedom!

Write an article for the first time, do not like spray, have a question welcome comment area message exchange!