0

Suppose I have an ever growing set of different templates to be used with react. Each template extends React.Component and renders fancy border around its children.

I expect to generate such templates (with caching etc.) on the fly from some data known only at run-time.

At run-time I can compute the name of the module containing the template. I can map an URL to a server code to provide JavaScript source and expect the browser to be able to run it.

I imagine that I would isolate this piece of code in a simple method similar loading a *.DLL by name and calling its exported symbol. My guess below does not work.

private async templateLoader():Promise<React.ComponentType>{
    const templateModuleName:string = this.props.api.getTemplateName(this.props.user);
    return (await import(templateModuleName)) as React.ComponentType;
}

I can imagine JavaScript using require.js like so

var propsMappedFromStore=this.props;
//...
require(["api","user"],function(api,user){
  var templateModuleName = api.getTemplateName(user);
  require([templateModuleName],function(tt){
   propsMappedFromStore.updateTemplate(tt);
  })
})

But is it possible with Typescript and Webpack?

How would I require/import the module identified by expression?

3
  • "My guess below does not work." What didn't work. I would expect dynamic imports to work with webpack code splitting. See this book for more info. Commented Jul 2, 2018 at 14:28
  • Code splitting does work. But the source of the "moment" module in the book is known at compile time, isn't it? I'm looking for a method where only interface is known but implementation evaluated at run-time. Perhaps I'm missing something. Commented Jul 2, 2018 at 14:49
  • Maybe you're looking for import types which are available in TS 2.9 Commented Jul 3, 2018 at 13:16

1 Answer 1

1

While working on a React application I came across this problem. The application is split in multiple modules. Among those modules there is a set with specific properties. Those modules can not participate in webpack building process. They do not exist at design and build time. Instead, I know only shape of their export.

To use those modules browser must use a loader. RequireJS AMD loader is a good choice.

It took me quite time to figure out how to make WebPack to play nicely with async loading. The keyword here was requirejs instead of require or import.

Usage of requirejs eliminate any magic with webpack.config.js or any other magic. The code below should give you an idea. Using statement requirejs(["locs/" + lang]…) leads to a http request at /{baseUrl}/locs/{lang}.js which is handled by web server according it smartness.

import { getLanguage, IGreetingFormatStrings } from "./lociface";
import { defGeetings } from "./config";

function getGreetings(lang: string): Promise<IGreetingFormatStrings> {
    return new Promise((resolve) => {
        requirejs(["locs/" + lang]
            , (m) => { resolve(m.locGreetings as IGreetingFormatStrings); }
            , () => { resolve(defGeetings) }
        )
    });
}

export async function greeter(person: string): Promise<string> {
    const hours = new Date().getHours();
    const greetings = await getGreetings(getLanguage());
    if (hours > 6 && hours < 12) {
        return greetings.morning + person;
    }
    if (hours < 19) {
        return greetings.afternoon + person;
    }
    return greetings.night + person;
}

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.