Search code examples
pathgulpgeneratorrequireaurelia

aurelia-cli generator cannot import dependencies


I'm using Aurelia-cli with typescript. There is a generator I made that requires a model file so it can iterate over its properties in order to generate the corresponding CRUD like this:

 let path = '../../src/modules/' + moduleName + '/models/' + modelFileName;
let mod = require(path);
let item = new mod[modelClassName]();

let keys = [];
for (var key in (item as any)){...}

Note that I have to require the model using a relative path here. This works well in the most simple cases. The problem comes when the model file has additional imports that use an absolute path (relative to the root of the project) like this:

import { EnumNodeTypeXx } from 'resources/enums/enum-node-type-xx';

Where the require() call fails with the following error:

    Error: Cannot find module 'resources/enums/enum-node-type-xx'
    at Function.Module._resolveFilename (module.js:469:15)
    at Function.Module._load (module.js:417:25)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> 
...

If I make use of a path relative to the model itself in the model file, the generator doesn't complain:

import { EnumNodeTypeXx } from '../../../resources/enums/enum-node-type-xx';

The problem happens also if I reference a file coming from an NPM module with imports.

Edit

After spending some time on aurelia-cli's code, I can see that it uses a (deprecated) nodejs feature where it overrides the processing of ts files by transpiling them before compiling them. After compilation, the problematic import is resolved with nodejs Module.require which can only require core modules, no_modules or relative path (according to the doc here: https://nodejs.org/docs/latest/api/modules.html#modules_file_modules

So, as the generator uses node for module resolution and the compilation uses typescript compilation, I seem to be stuck. Does anyone see a way out of this?


Solution

  • So, there doesn't seem to be an easy answer to this. I ended up overriding the require() method to handle my absolute paths differently as explained here and pointed by zewa666 in my github issue.

     const moduleProto = Object.getPrototypeOf(module)
      const origRequire = moduleProto.require
      moduleProto.require = function(request) {
        if (request.startsWith('resources') 
      || request.startsWith('services') 
      || request.startsWith('modules')) {//very naive approach but easy enough to understand
    request = __dirname + '/../../src/' + request + '.ts';
    
      }
      return origRequire.call(this, request);
          }