Automatische Aktualisierung von Skripten nach der Bereitstellung

Prolog





Guten Tag, liebe Leser. Dieser Artikel befasst sich mit einem Problem, mit dem Entwickler mehr oder weniger schwerwiegender Websites konfrontiert sind, nämlich dem Problem der automatischen Aktualisierung von Skripten im Browser des Benutzers nach der Bereitstellung.



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



, 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.

C# , JS . .



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



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