How to protect shared objects on the front end

How to protect shared objects on the front end

What is shared object

The same object used multiple times is a shared object

For example, we use a standard esmodule to write a module that exports unit conversion

//converter module
export default {
    cmToIn(){
       //convert logic
    }
} 

When we use this module in other modules, converterit is a shared object, and there is only one copy in the memory, no matter importhow many times it has been used .

In the same way, the object collection shown above is a collection of common methods. In the front-end project, we will also encapsulate some so-called data sets in a certain module to facilitate later modification. For example, when we implement a constantconstant module, we put some projects Put in the data that may be modified later

//constant
export default {
    dateFormatter:'YYYY-MM-DD',
    reports:{
        productId:'123',
        productName:'456'
    }
} 

Here is just a hint

Why protect shared objects

Prevent shared objects from being accidentally modified and causing online failures

In principle, we will not and will not intentionally modify the data in these common modules in our business code, especially modules like this. If we want to modify, we must modify this module.

However, there are always surprises in everything. For example, we have a scenario where we can judge whether a user can display a report based on the information returned by the backend and some constants on the frontend . The code we expect may be like this

import Constant from './constant';//constant 
//... 
export default View.extend({
    render(){
       //... 
        if(Constant.reports.productId==user.reportProductId){
           //....
        }
    }
}); 

Note that the ifstatement in the above code , if it is wrongly written as:, if(Constant.reports.productId=user.reportProductId)the comparison of two equal signs is written as an equal sign assignment.

If during the self-test, the same is user.reportProductIdreturned in the user interface 123, then assign the value first, then make the ifjudgment, and it is established. As a developer, you will mistakenly think that the logic here is OK. Of course, under normal circumstances, the user interface should also be tested if it user.reportProductIdis not returned 123. At this time, the problem may be found.

If, after the above-mentioned problems have not tested out, everything went wrong on the line, the problem for a large single-page application is fatal, if a user reportProductIdis 456, after visiting the wrong page, because the accident changed constantthe reports.productId, It will cause 123problems when reading other modules in the future.

How to protect shared objects

const

The const keyword declaration only prevents the variable from being reassigned and cannot prevent the object from being modified

Object.freeze

It can be prevented from being modified, but if the object is nested, the nested object can still be modified, requiring the developer to freezerecursively traverse the desired object freeze. The most important point is that when I modify an freezeobject, although the modification is unsuccessful, there is no hint that the task has failed. In the aforementioned scenario, we still hope that the developer can promptly modify an object that is not allowed to be modified. Give the corresponding prompt.

Proxy

es6 new method of proxy operation object

ProxyThere are many related articles, so I won t go into details here. We use Proxyto implement a Safeguardmethod to protect our shared objects.

const Safeguard = o => {
    let build = o => {
        let entity = new Proxy(o, {
            set() {
                throw new Error('readonly');
            },
            get(target, property) {
                let out = target[property];
                if (target.hasOwnProperty(property) &&
                    (Array.isArray(out) ||
                        Object.prototype.toString.call(out) == '[object Object]')) {
                    return build(out);
                }
                return out;
            }
        });
        return entity;
    };
    return build(o);
} 

The code is simplified here, you can adjust the corresponding implementation logic according to your needs

use

const user=Safeguard({
    name:' ',
    address:{
        city:'hz'
    }
}); 

This userobject can only be read but not written. When the developer tries to write new data, an error will be thrown to remind the developer

scenes to be used

Address bar resolution object

In a single-page application, we need to parse the string address in the address bar into an object for us to use.

For example /path/name?a=b&c=d, we might parse into such an object

{
    path:'/path/name',
    params:{
        a:'b',
        c:'d'
    }
} 

If you have counted your single-page applications, you will find that fixed users always only visit certain pages. We can temporarily parse the address string in the address bar when the user visits a certain page, or we can The analysis result is stored. When the user visits this page again, there is no need to analyze it, just use the saved result.

I have written Magix.Cache about this one , to explain in detail how to intelligently cache what information is needed

For the cached address bar information object, it is a shared object. To ensure that it cannot be written by the developer with a new value, you can use the Safeguardmethod we defined earlier to protect it.

Cached interface data

In single-page application development, some data needs to be provided by the back-end, but the data provided by the back-end may not be modified for a long time, such as provincial and municipal data. The front-end does not need to use this data every time It is requested once every time, so the front-end can cache the data of this interface to save requests

For such data objects, protection is also needed. In short, as long as they are shared objects, they need to be protected from accidental modification.

About going online

The Safeguardmethod we talked about earlier , in my opinion, does not need to be published online, as long as the development phase exists. As long as it is ensured that there is no write operation to the shared object during development, there must be no write operation when it is posted online. At this time, this protection Safeguardmethod is redundant.

How to protect it during development and remove it when it is published online?

We can use uglifythis code compression tool global_defsconfiguration. For example, define it like this in the development phase

if (typeof DEBUG == 'undefined') window.DEBUG = true;
//...

const user={
    name:' ',
    address:{
        city:'hz'
    }
}

if(DEBUG){
    user=Safeguard(user);
} 

Then when compressing:

uglify({
    compress: {
        global_defs: {
            DEBUG: false
        }
    },
    output: {
        ascii_only: true
    }
}); 

Then the compressed code does not contain DEBUGrelated statements

Of course, Safeguardthere is no big problem following the online. The last part of "About the online" is just for a more in-depth discussion. If you Safeguardwant to go online, pay attention Proxyto compatibility.