Dynamically load modules with Webpack using Typescript

倾然丶 夕夏残阳落幕 提交于 2019-12-29 13:33:51

问题


I'm trying to build a web app which supports plugins, the environment is Angular 2 (so far), Typescript 2.1 and Webpack 2. I have some extension points (slots) where plugins can draw their content in: basically I have a component which is capable of hosting some other component known at runtime (see "Mastering Angular 2 Components" chapter 10 for the idea, and SO + plunker on how compile and "draw" at runtime an Angular component)

Here's what I want to achieve:

// in plugin.service.ts
loadPlugin(url)
{
    return System.import('absolute OR relative ?? plugin base path' + name)
           .then((pluginModule) => {
               const Plugin = pluginModule.default;
               // then use the plugin
    });
}

...

//content of the plugin file being imported
export default class HeaderButtonsPlugin {
    constructor() {}
    //useful things about the plugin
}

I'm importing modules at runtime using System.import from Webpack, although I know is deprecated, AFAIK it's the only way to import modules dynamically using typescript, since import is not yet supported by typescript itself (reference here). (is there any other ways to accomplish this?)

Now, just for testing the system, I included the plugin directory in the same root of the application (the src dir), using the directory tree below; beware that this causes webpack to know at compile time the existence of the plugin code, and to pack both the plugin and the application in the same bundle's set, it's a semplification in order to test the plugin architecture capabilities; here's the folders tree:

- src
    - app
        - core
            - plugin.service.ts
    - plugins
        - pluginA
            - pluginA.plugin.ts

in this way if I import the pluginA.plugin.ts with System.import('relativePathToPluginA') everything works as expected: the system is able to load and compile the plugin component and use it as well.

But, in a real world scenario, the plugin must not be known at compile time so I created a new project using angular-cli, and added the pluginA directory, then I referenced it in its app.module. Then I built the project and moved the js output in a folder, let's say D:\pluginDist\. Then I referenced the main.bundle.js from the loadPlugin method above, like in the below example (with url = 'main.bundle.js')

loadPlugin(url)
{
    return System.import('D:\\pluginDist\\' + url)
           .then((pluginModule) => {
               const Plugin = pluginModule.default;
               // then use the plugin
    });
}

I don't know if referencing the main boundle is correct (I lack some webpack's concepts for sure) but it is at least the building artifact, so I give it a try. This way I have the error Unhandled Promise rejection: Cannot find module 'D:\pluginDist\main.bundle.js'. ; Zone: angular ; Task: Promise.then ; Value:

Other tests I did were

  • transpile the *.ts files in the plugin project, skipping webpack at all, so just typing tsc in the command line, and try to import the pluginA.plugin.ts transpilation result, I had the same error as above.

  • put the js result (both from webpack or from plain tsc transiplation) in the folder where the development web server actually serves the files (.tmp) and then referencing them through a relative path: this causes webpack to stop at compile time because, of course, it doesn't find the files in the project directory tree while packing.

Now I don't know where to head for, do you have any advice??

What I want to achieve is to load, dynamically, using webpack and typescript, a js module, that is not known at compile time.


回答1:


In Webpack.config.js update below code.

The resolver is used to load files relative to the src root and by resolving app folder in webpack.config.js, file within that folder can be accessed by absolute path as shown above.

resolve: {
    extensions: ['.ts', '.js', 'css'],
    "modules": [
        "./node_modules",
        "src"
    ]
},

output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
        publicPath: 'dist/',
    }

And in your system.import as below: where app is the folder inside your src folder

System.import('app/+ url').then(fileInstance=> {          
    console.log(fileInstance);            
});


来源:https://stackoverflow.com/questions/43087156/dynamically-load-modules-with-webpack-using-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!