New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript Path Mapping #1082

Closed
joelhoward0 opened this Issue Mar 24, 2017 · 7 comments

Comments

Projects
None yet
4 participants
@joelhoward0

joelhoward0 commented Mar 24, 2017

Issue description or question

Since updating my project to use Typescript 2's Path Mapping feature, wallaby reports 'cannot find modules' errors suggesting that the 'paths' part of my tsconfig isn't being used properly (or something like that). In the error below, 'hex' module is on physical path /domain/hex/hex, aliases to /hex/hex in the tsconfig.

Note that if I change the path to 'domain/hex/hex', it works - so 'baseUrl' seems to be working, but not the mapped paths. Details below, thanks!

Wallaby TS version:

console.log('Wallaby ts version:', require('typescript').version); 
prints Wallaby ts version: 2.2.1
[Error]: Runtime error: Error: Cannot find module 'hex/hex'​​
​​[Error]:     at Function.Module._resolveFilename (module.js:469:15)​​
​​[Error]:     at Function.Module._load (module.js:417:25)​​
​​[Error]:     at Module.require (module.js:497:17)​​
​​[Error]:     at require (internal/module.js:20:19)​​
​​[Error]:     at Object.<anonymous> (.\tests\hex-tests.js:6:28)​​

the relevant line in the test file:

import { Hex } from 'hex/hex'`

tsconfig.json configuration file

{
  "compilerOptions": {
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "./compiledts",
    "target": "es6",
    "baseUrl": ".",
    "paths": {
      "routes/*": ["client/components/routes/*"],
      "components/*": ["client/components/*"],
      "hex/*": ["domain/hex/*"]
    }
  },
  "exclude": [
      "node_modules",
      "typings/browser",
      "typings/browser.d.ts"
  ],
  "compileOnSave": false,
  "atom": {
      "rewriteTsconfig": false
  }
}

Wallaby.js configuration file

module.exports = function(wallaby) {
  return {
    files: [
      'domain/hex/*.ts'
    ],
    tests: [
      'tests/hex-tests.ts'
    ],
    env: {
      type: 'node'
    },
    workers: {
      initial: 1,
      regular: 1
    }
  }
}

Code editor or IDE name and version

Sublime Text v3

OS name and version

Windows

@ArtemGovorov

This comment has been minimized.

Show comment
Hide comment
@ArtemGovorov

ArtemGovorov Mar 24, 2017

Member

TypeScript compilation doesn't change the the import's. The path mapping feature is just really a dev time thing, so one needs to do the runtime mapping depending on the platform. In node.js, one way to do would be to use the NODE_PATH env variable to give node.js a hint how to resolve the hex/hex like paths.

module.exports = function(wallaby) {
  var path = require('path');
  process.env.NODE_PATH += 
    path.delimiter + path.join(wallaby.projectCacheDir, 'client/components') +
    path.delimiter + path.join(wallaby.projectCacheDir, 'domain');

  return {
    ...
  }
}
Member

ArtemGovorov commented Mar 24, 2017

TypeScript compilation doesn't change the the import's. The path mapping feature is just really a dev time thing, so one needs to do the runtime mapping depending on the platform. In node.js, one way to do would be to use the NODE_PATH env variable to give node.js a hint how to resolve the hex/hex like paths.

module.exports = function(wallaby) {
  var path = require('path');
  process.env.NODE_PATH += 
    path.delimiter + path.join(wallaby.projectCacheDir, 'client/components') +
    path.delimiter + path.join(wallaby.projectCacheDir, 'domain');

  return {
    ...
  }
}

@ArtemGovorov ArtemGovorov changed the title from tsconfig 'path mapping' not working with wallaby in Sublime Text 3 to Typescript Path Mapping Mar 24, 2017

@joelhoward0

This comment has been minimized.

Show comment
Hide comment
@joelhoward0

joelhoward0 Mar 24, 2017

Thanks for the help! I had to tweak your supplied code to reference the wallaby project cache, instead of the local project directory. My version of what you supplied looked like this:

module.exports = function(wallaby) {
  var path = require('path');

  process.env.NODE_PATH += 
    path.delimiter + path.join(wallaby.projectCacheDir, 'client/components') +
    path.delimiter + path.join(wallaby.projectCacheDir, 'domain');

joelhoward0 commented Mar 24, 2017

Thanks for the help! I had to tweak your supplied code to reference the wallaby project cache, instead of the local project directory. My version of what you supplied looked like this:

module.exports = function(wallaby) {
  var path = require('path');

  process.env.NODE_PATH += 
    path.delimiter + path.join(wallaby.projectCacheDir, 'client/components') +
    path.delimiter + path.join(wallaby.projectCacheDir, 'domain');
@ArtemGovorov

This comment has been minimized.

Show comment
Hide comment
@ArtemGovorov

ArtemGovorov Mar 25, 2017

Member

Awesome, thanks for the update! Have updated my answer to use projectCacheDir, sorry about forgetting about it initially.

Member

ArtemGovorov commented Mar 25, 2017

Awesome, thanks for the update! Have updated my answer to use projectCacheDir, sorry about forgetting about it initially.

@myflowpl

This comment has been minimized.

Show comment
Hide comment
@myflowpl

myflowpl Dec 15, 2017

I just run on the same issue, and find out more stable solution
install tsconfig-paths package in your project
create new file wallaby-paths.js next to your wallaby.js and tsconfig.json files

// ./wallaby-paths.js
const tsConfigPaths = require('tsconfig-paths');
const tsconfig = require('./tsconfig.json');
tsConfigPaths.register({
  baseUrl: tsconfig.compilerOptions.baseUrl,
  paths: tsconfig.compilerOptions.paths
});

add env config to your wallaby.js file

// ./wallaby.js 
...
    env: {
      type: 'node',
      params: {
        runner: '-r ' + path.join(__dirname, './wallaby-paths.js')
      }
    },
...

this way you manage your paths only in one place, inside tsconfig.json, and you don't mess with NODE_PATHS directly

BTW
@ArtemGovorov use of tsconfig paths should be build into wallaby.js, or at least the manual configuration should be added to official documentation, be course custom paths are becoming more and more used.
But, anyway, Wallaby ROCKS 🥇

myflowpl commented Dec 15, 2017

I just run on the same issue, and find out more stable solution
install tsconfig-paths package in your project
create new file wallaby-paths.js next to your wallaby.js and tsconfig.json files

// ./wallaby-paths.js
const tsConfigPaths = require('tsconfig-paths');
const tsconfig = require('./tsconfig.json');
tsConfigPaths.register({
  baseUrl: tsconfig.compilerOptions.baseUrl,
  paths: tsconfig.compilerOptions.paths
});

add env config to your wallaby.js file

// ./wallaby.js 
...
    env: {
      type: 'node',
      params: {
        runner: '-r ' + path.join(__dirname, './wallaby-paths.js')
      }
    },
...

this way you manage your paths only in one place, inside tsconfig.json, and you don't mess with NODE_PATHS directly

BTW
@ArtemGovorov use of tsconfig paths should be build into wallaby.js, or at least the manual configuration should be added to official documentation, be course custom paths are becoming more and more used.
But, anyway, Wallaby ROCKS 🥇

@ArtemGovorov

This comment has been minimized.

Show comment
Hide comment
@ArtemGovorov

ArtemGovorov Dec 18, 2017

Member

@myflowpl Awesome, thanks for the post. We have added the docs section describing various ways to handle the scenario.

BTW, I think you can implement your idea without an additional file, just with the setup function.

Member

ArtemGovorov commented Dec 18, 2017

@myflowpl Awesome, thanks for the post. We have added the docs section describing various ways to handle the scenario.

BTW, I think you can implement your idea without an additional file, just with the setup function.

@myflowpl

This comment has been minimized.

Show comment
Hide comment
@myflowpl

myflowpl Dec 18, 2017

@ArtemGovorov it's awesome, really clear solution, thanks

myflowpl commented Dec 18, 2017

@ArtemGovorov it's awesome, really clear solution, thanks

@pndewit

This comment has been minimized.

Show comment
Hide comment
@pndewit

pndewit Mar 27, 2018

The above solutions didn't seem to work for me in combination with either this workaround that I have implemented or with my setup. After some struggling I came up with this solution, hope it will help anyone:

setup: (wallaby => {
    wallaby.delayStart();

    requirejs.config({
        // This part is different from the original workaround
        paths: {
            // paths
        },
        packages: [
            // packages
        ]
    });

    require(['test/unit/setup.js'].concat(wallaby.tests), () => {
        wallaby.start();
    });
})
    .toString()
    .replace('// packages', aureliaJson.build.bundles.reduce((depList, bundle) => {
        return depList + (bundle.dependencies || []).reduce((prev, curr) => {
            let moduleName, modulePath, moduleMain;
            if(curr.path) {
                moduleName = moduleMain = curr.name;
                modulePath = path.relative(
                    __dirname,
                    path.resolve(__dirname, 'aurelia_project', curr.path))
                    .split('\\').join('/');
                if(curr.main) {
                    moduleMain = curr.main;
                }
            } else {
                moduleName = moduleMain = curr;
                modulePath = 'node_modules/' + moduleName + '/dist/amd';
            }
            return prev
                + '{ name: ' + JSON.stringify(moduleName)
                + ', location: ' + JSON.stringify(modulePath)
                + ', main: ' + JSON.stringify(moduleMain)
                + '},';
        }, '');
    }, ''))

    // This part is different from the original workaround
    .replace('// paths', Object.keys(aureliaJson.paths).reduce((pathList, path) => {
        return pathList + path + ': ' + JSON.stringify(aureliaJson.paths[path]) + ',';
    }, ''))

In short I added 2 new pieces (highlighted with a comment):

paths: {
    // paths
},

This is used to be replaced by the second piece (like the original workaround does with the packages).

.replace('// paths', Object.keys(aureliaJson.paths).reduce((pathList, path) => {
    return pathList + path + ': ' + JSON.stringify(aureliaJson.paths[path]) + ',';
}, ''))

This adds the paths (aliases) inside my aurelia_project/aurelia.json to the requirejs config. I am now also able to map unknown paths to known paths (e.g. mapping: "root" to "src" which is added by the Aurelia CLI by default).

EDIT: A little off-topic but maybe interesting for those implementing my workaround; To make this work nicely with my IDE I also had to add the following config to my tsconfig.json inside the compilerOptions object:

"baseUrl": ".",
"paths": {
  "root/*": ["src/*"],
  "resources/*": ["src/app/resources/*"],
  "elements/*": ["src/app/resources/elements/*"],
  "attributes/*": ["src/app/resources/attributes/*"],
  "valueConverters/*": ["src/app/resources/value-converters/*"],
  "bindingBehaviors/*": ["src/app/resources/binding-behaviors/*"]
}

pndewit commented Mar 27, 2018

The above solutions didn't seem to work for me in combination with either this workaround that I have implemented or with my setup. After some struggling I came up with this solution, hope it will help anyone:

setup: (wallaby => {
    wallaby.delayStart();

    requirejs.config({
        // This part is different from the original workaround
        paths: {
            // paths
        },
        packages: [
            // packages
        ]
    });

    require(['test/unit/setup.js'].concat(wallaby.tests), () => {
        wallaby.start();
    });
})
    .toString()
    .replace('// packages', aureliaJson.build.bundles.reduce((depList, bundle) => {
        return depList + (bundle.dependencies || []).reduce((prev, curr) => {
            let moduleName, modulePath, moduleMain;
            if(curr.path) {
                moduleName = moduleMain = curr.name;
                modulePath = path.relative(
                    __dirname,
                    path.resolve(__dirname, 'aurelia_project', curr.path))
                    .split('\\').join('/');
                if(curr.main) {
                    moduleMain = curr.main;
                }
            } else {
                moduleName = moduleMain = curr;
                modulePath = 'node_modules/' + moduleName + '/dist/amd';
            }
            return prev
                + '{ name: ' + JSON.stringify(moduleName)
                + ', location: ' + JSON.stringify(modulePath)
                + ', main: ' + JSON.stringify(moduleMain)
                + '},';
        }, '');
    }, ''))

    // This part is different from the original workaround
    .replace('// paths', Object.keys(aureliaJson.paths).reduce((pathList, path) => {
        return pathList + path + ': ' + JSON.stringify(aureliaJson.paths[path]) + ',';
    }, ''))

In short I added 2 new pieces (highlighted with a comment):

paths: {
    // paths
},

This is used to be replaced by the second piece (like the original workaround does with the packages).

.replace('// paths', Object.keys(aureliaJson.paths).reduce((pathList, path) => {
    return pathList + path + ': ' + JSON.stringify(aureliaJson.paths[path]) + ',';
}, ''))

This adds the paths (aliases) inside my aurelia_project/aurelia.json to the requirejs config. I am now also able to map unknown paths to known paths (e.g. mapping: "root" to "src" which is added by the Aurelia CLI by default).

EDIT: A little off-topic but maybe interesting for those implementing my workaround; To make this work nicely with my IDE I also had to add the following config to my tsconfig.json inside the compilerOptions object:

"baseUrl": ".",
"paths": {
  "root/*": ["src/*"],
  "resources/*": ["src/app/resources/*"],
  "elements/*": ["src/app/resources/elements/*"],
  "attributes/*": ["src/app/resources/attributes/*"],
  "valueConverters/*": ["src/app/resources/value-converters/*"],
  "bindingBehaviors/*": ["src/app/resources/binding-behaviors/*"]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment