Actualización automática de scripts después de la implementación

Prólogo





Buenas tardes queridos lectores. Este artículo está dedicado al problema que enfrentan los desarrolladores de sitios web más o menos serios, a saber, el problema de actualizar automáticamente los scripts en el navegador del usuario después de la implementación.



, , , , , , , . , , . – , , .



, F5, , , .







, .



, , VueJS 2.6.x, js- webpack'.



-, , github.



:



-

github



, , . , , .





- .



, , . , , .





Vue, /src/plugins/AutoReload. npm .



- vue-cli, : store, , axios - dayjs . Element.





– . :



  • . API, (, , ). , , .
  • . – , , , . , .
  • . .


, VueJS Webpack. , webpack js-, . , , version.json, .



, (development/production/etc.) package.json. :



{
    "AppVersion": "1.0.0",
    "Build": "development",
    "BundleVersion": "2020-11-07T10:42:33.731Z"
}


, vue.config.js, :



const path = require('path');

//   version.json   
const AutoReloadUtils = require('./src/plugins/AutoReload/versionGenerator');
AutoReloadUtils.generateVersionFile(path.resolve(path.join(__dirname, 'public/version.json')));

module.exports = {
    ...
};


version.json:



versionGenerator.js
const path = require('path');
const fs = require('fs');

module.exports = {
    /**
     *     
     * @param {String} filename    
     */
    generateVersionFile: function (filename) {
        //     package.json
        const packageJson = fs.readFileSync('./package.json');
        const version = JSON.parse(packageJson).version || 0;

        fs.writeFileSync(filename, `{
    "AppVersion": "${version}",
    "Build": "${process.env.NODE_ENV}",
    "BundleVersion": "${new Date().toISOString()}"
}
`);
    }
}




serve, build version.json, get-, .



№1. version.json public, VueJS « ». .



№2. version.json git', , .



AutoReload



:



  1. , .
  2. vue-router, . . Vue , , , , ( ) . .
  3. .




. , , :



  • Enabled – , true.
  • CheckInterval – , 60. .
  • Notification – , true. , «», .
  • NotificationMessage – , « , .». Element, , . , , alert.


.



Config.js
import { isBoolean } from './utils';

/**
 *    
 */
export default class Config {
    /**
     * 
     * @param {Object} origin 
     */
    constructor(origin) {
        /**
         *   
         * @type {Boolean}
         */
        this.Enabled = isBoolean(origin.Enabled) ? origin.Enabled : true;

        /**
         *      
         * @type {Number}
         */
        this.CheckInterval = origin.CheckInterval ?? 1 * 60;

        /**
         *     
         * @type {Boolean}
         */
        this.Notification = isBoolean(origin.Notification) ? origin.Notification : true;

        /**
         *  
         * @type {String}
         */
        this.NotificationMessage = origin.NotificationMessage
            ?? '  ,   .';
    }
}






, – Element', create Vue:



import AutoReload from '@/plugins/AutoReload';
...
new Vue({
    router,
    store,

    created() {
        Vue.use(AutoReload, {
            config: {
                //  
                Enabled: true,
                //  
                CheckInterval: 60,
            },
            router: this.$router,
            vm: this,
        });
    },

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








AutoReload.js
import Config from './Config';
import { getVersion } from './utils';

/** @typedef {import('./Version').default} Version */

/**
 *   
 */
export default class AutoReload {
    /**
     * 
     * @param {Object} options 
     */
    constructor(options) {
        /**   */
        this.router = options.router;

        /**  Vue */
        this.vm = options.vm;

        /**  */
        this.config = new Config(options.config);

        /**
         *   
         * @type {Version}
         */
        this.lastVersion = null;

        /**
         *   
         * @type {Number}
         */
        this.timer = null;
    }

    /**   */
    async init() {
        const config = this.config;

        if (config.Enabled) {
            //    
            this.lastVersion = await getVersion();

            if (this.lastVersion && config.CheckInterval > 0) {
                //    
                this.timer = setInterval(async () => {
                    this.check();
                }, config.CheckInterval * 1000);
            }

            //    
            this.router.beforeEach(async (to, from, next) => {
                await this.check(this.router.resolve(to).href);
                next();
            });
        }
    }

    /**
     *    
     * @param {String} href  
     */
    async check(href) {
        //    
        const version = await getVersion();

        if (this.lastVersion.BundleVersion != version.BundleVersion) {
            //   

            //  
            if (this.timer) {
                clearInterval(this.timer);
                this.timer = null;
            }

            if (this.config.Notification) {
                //    
                await this.vm.$alert(this.config.NotificationMessage, '', {
                    type: 'warning',
                    confirmButtonText: 'OK',
                    closeOnClickModal: true,
                    closeOnPressEscape: true,
                }).catch(() => { });
            }

            //    
            //   ,     ,
            //        ,    
            this.lastVersion = await getVersion();

            this.reload(href);
        }
    }

    /**
     *  
     * @param {String} href  
     */
    reload(href) {
        if (href) {
            window.location.href = href;
        } else {
            window.location.reload(true);
        }
    }
}




check href. , .



version.json . , , .



, F5 (window.location.reload(true)). , . , .. next() .



, .



№1.



version.json . «» , , URL. , version.json .



, , . , , .



, .



, : «60 », «60 ». , . , .



№2.

La solución original se escribió en C # hace muchos años y luego se transfirió a JS casi sin cambios. Proporcionaré el código para soluciones y ejemplos de uso.



Fuente en C #: https://pastebin.com/T1PsMy4N



Fuente JS: https://pastebin.com/a4z25b1H



:



//   
var windows0 = WordForm.get(0, "", "", "");  // ""
var windows1 = WordForm.get(1, "", "", "");  // ""
var windows2 = WordForm.get(2, "", "", "");  // ""

//       
var totalWindows0 = WordForm.getAsCount(0, "", "", "");  // "0 "
var totalWindows1 = WordForm.getAsCount(1, "", "", "");  // "1 "
var totalWindows2 = WordForm.getAsCount(2, "", "", "");  // "2 "






, , , . .







, - , , , . , - -, - .



? , , , , , , .



- , : , .







, , , . js- . .



, / , . , , – .







, , . , store. , , .



, , : .







, , - changelog', . , . , . , , .





, .



, , .





, . , «», ?



? :






All Articles