vendredi 31 juillet 2020

Using Reflection with Classes and JavaScript Modules

I'm at the point where I've spent over 8 hours tinkering with this and would love some advice. My objective is to implement the approach which is most likely to be native to JavaScript at some point in the future. I want the solution to work both in web browsers and on a Node server. That being the case, I want to avoid anything besides vanilla JavaScript as much as possible.

Here is my dilemma. I have two classes, each in their own file. My problem is shown in the get() method of the Model class.

ChildModel.js

import Model from './Model.js';

class ChildModel extends Model {

    // Data which describes where data is stored on the server
    static meta = {
        url: 'api/child-model/';
    }

}

export default = ChildModel;

Model.js

class Model {

    // A convenient method which all models use to get their data from the server
    async get() {
        // Use reflection to get the name of the extended child class
        var modelClassName = this.name; // "ChildModel"

        // Nice, now I know the name of my class
        // Now, I just need to get to the actual class definition so I can access the static .meta property
        // I have three options that I can think of to do this:

        // Option 1 - Use a global
        var ModelClass = window[modelClassName]; // or global[modelClassName]
        // Pros: looks straightforward
        // Cons: pollutes the global namespace and requires me to write 
        // nasty code to put all of my models onto window or global.
        // Does not work because inside module there is no access to window or global

        // Option 2 - Use require()
        var ModelClass = require('./models/'+modelClassName+'.js');
        // Pros: works perfectly on server side in Node
        // Cons: does not work at all in the browser without third party software

        // Option 3 - Use import()
        var importedModelClass = await import('./models/'+modelClassName+'.js');
        var ModelClass = importedModelClass.default;
        // This is basically the same as Option 2

        // Option 4 - ???
    }

}

export default = Model;

To solve the issue for now, I'm currently using Rollup to put all of my files into a single index.js file. I am then using a dynamic import plugin to implement option #3. It works, but I am sitting here at the end of coding all day and thinking this can't be the best way to do things in 2020. Did I miss something obvious or is this how it's done?





Aucun commentaire:

Enregistrer un commentaire