Pembaruan otomatis skrip setelah penerapan

Prolog





Selamat siang, pembaca yang budiman. Artikel ini dikhususkan untuk masalah yang dihadapi oleh pengembang situs web yang kurang lebih serius, yaitu masalah memperbarui skrip secara otomatis di browser pengguna setelah penerapan.



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



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





, .



, , .





, . , «», ?



? :



  • , : ,

  • JavaScript

  • Mengisi template teks dengan data berbasis model. Implementasi .NET menggunakan fungsi dinamis dalam bytecode (IL)




All Articles