'Typescript configure mapping for compiled import path

I have an aws amplify project which is using yarn workspaces.

My project has a lambda function and a layer. When the lambda function runs in aws it needs to import my library from the layer...

import MyLib from '/opt/nodejs/build/MyLib';

However when I run this function locally I want to import the library from my local file system

import MyLib from '/Users/sive/Documents/SWT/wake-book/amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib';

How can I tell typescript to compile an import from /opt/nodejs/build/MyLib to the location on my local file system.

I tried using path mapping in my tsconfig.json

    "baseUrl": ".",
    "paths": {
      "/opt/nodejs/build/MyLib": ["./amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib.d.ts"]
    },

This stops vscode complaining about an unknown import, so it is being 'linked' correctly (I can cmd click my import /opt/nodejs/build/MyLib path and I am taken to the full file system path.)

But the compiled js is still using the wrong path.

The compiled js file looks like this

const MyLib_1 = __importDefault(require("/opt/nodejs/build/MyLib"));

I would expect it to remap the import path and to look like this

const MyLib_1 = __importDefault(require("/Users/sive/Documents/SWT/wake-book/amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib"));

If I manually edit the output js to have the full file system path it works (I can run my project locally).

  1. Have I misunderstood how path mapping is supposed to work?
  2. Is there a way to get my desired behaviour?


Solution 1:[1]

It's been a year and a half since this post was first answered, and there still doesn't seem to be a widely publicized solution to this issue.

So in case anyone stumbles upon this, here's what I came up with:

I have a JAVASCRIPT (.js, not a .ts file) in all my lambda function handler directories whose single responsibility is to import the layer, at run time, from the appropriate path (at either the '/opt/nodejs' path or the local path on my computer). It does so using a try/catch mechanism, which I know is a sort of anti-pattern, but it works well for this scenario.

  try{
      module.exports = require("/opt/nodejs/index")
  } catch { 
      module.exports = require("../../layer/index"); // my local path  
  }

Then, in my handler code I import the layer with this code snippet:

import layer = require("../../layer"); // path to aforementioned file

This solution is leveraging an obscure typescript feature referred to as 'export = syntax'

https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require

It only works if the file that imports the switching layer code is a javascript (.js) file. It doesn't work if it's a typescript (.ts) file. So you'll also have to configure your tsconfig.json file with "allowJs": true

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Http417