Skip to content

Instantly share code, notes, and snippets.

@azarus
Last active March 7, 2022 20:31
Show Gist options
  • Save azarus/f369ee2ab0283ba0793b0ccf0e9ec590 to your computer and use it in GitHub Desktop.
Save azarus/f369ee2ab0283ba0793b0ccf0e9ec590 to your computer and use it in GitHub Desktop.
Gulp Task to transform Typescript path imports into relative paths using the tsconfig
// Gulp Task
gulp.task("compile:source", function(done) {
gutil.log(gutil.colors.yellow("[Typescript]"), gutil.colors.magenta('Transpiling Source'));
var tsProject = ts.createProject('tsconfig.json', {
typescript: require('typescript'),
});
gulp.src("source/**/*")
.pipe(tsProject())
.pipe(tsimport(tsProject.config.compilerOptions))
.on('error', function(error, callback)
{
gutil.log(gutil.colors.red("[Typescript] Server Error:"), error.stack);
this.emit("end");
})
.pipe(gulp.dest("build/"))
.on("end", done);
});
var through = require('through2');
var replacePath = require("./replace-path.js");
module.exports = function(importOptions)
{
return function(file)
{
return through(function (buffer, enc, cb)
{
var code = buffer.toString("utf8");
code = replacePath(code, file, importOptions.baseUrl, importOptions.paths);
buffer = new Buffer(code);
this.push(buffer);
cb();
});
}
};
var fs = require("fs");
var path = require("path");
module.exports = function(code, filePath, rootPath, targetPaths)
{
var tscpaths = Object.keys(targetPaths);
var lines = code.split("\n");
return lines.map((line) =>
{
var matches = [];
var require_matches = line.match(/require\(('|")(.*)('|")\)/g);
// var import_matches = line.match(/import ('|")(.*)('|")/g);
Array.prototype.push.apply(matches, require_matches);
if(!matches)
{
return line;
}
// Go through each require statement
for(var match of matches)
{
// Find each paths
for(var tscpath of tscpaths)
{
// Find required module & check if its path matching what is described in the paths config.
var requiredModules = match.match(new RegExp(tscpath, "g"));
if(requiredModules && requiredModules.length > 0)
{
for(var requiredModule of requiredModules)
{
// Skip if it resolves to the node_modules folder
var modulePath = path.resolve('./node_modules/' + tscpath);
if (fs.existsSync(modulePath))
{
continue;
}
// Get relative path and replace
var sourcePath = path.dirname(filePath);
var targetPath = path.dirname(path.resolve(rootPath + "/" + targetPaths[tscpath]));
var relativePath = path.relative(sourcePath, targetPath)
line = line.replace(new RegExp(tscpath, "g"), "./" + relativePath + "/");
}
}
}
}
return line;
}).join("\n");
};
var through = require('through2');
var replacePath = require("./replace-path.js");
module.exports = function(importOptions)
{
return through.obj(function (file, enc, cb)
{
var code = file.contents.toString('utf8');
code = replacePath(code, file.history.toString(), importOptions.baseUrl, importOptions.paths);
file.contents = new Buffer(code);
this.push(file);
cb();
});
};
var tsify = require('tsify');
var importify = require("./typescript/importify.js");
var tsconfig = require("../tsconfig.json");
function CompileSources(entryFile)
{
var bundler = watchify( browserify({
entries: entryFile,
debug: false,
// defining transforms here will avoid crashing your stream
})
.plugin(tsify, tsconfig.compilerOptions))
.transform(importify(tsconfig.compilerOptions))
// .. etc
}
@prograhammer
Copy link

Is this in an npm package anywhere? That's so weird that typescript doesn't do this!??

@kirakishin
Copy link

@prograhammer i think the exact same thing !

@spentak
Copy link

spentak commented Nov 29, 2017

Yo this is cool but it doesn't parse directories within directories. Some bad regex I think

@salchichongallo
Copy link

salchichongallo commented Dec 17, 2017

Hi! I just built a package based on this. It's called path-alias-resolver

@yadue
Copy link

yadue commented Dec 21, 2017

@salchichongallo how to use your plug-in?

@jazzfog
Copy link

jazzfog commented Feb 6, 2018

Awesome!
One small bug on Windows though: Windows-style back-slash that comes from path.relative in relativePath breaks require().
Need to replace it to regular slash (/):

in replace-path.js
after
var relativePath = path.relative(sourcePath, targetPath)
add
relativePath = relativePath.replace(/\\/g, '/');

@Alex66955
Copy link

I have two issues with your script:

  • If the tsconfig.json provides an outDir attribute not even ".":
    • the relative path replacement didn't work correctly. It generates the relative path from outDir to sourceDir which should not happened.
    • the import replacement should be independent from the outDir attribute
    • my current workaround is to remove the outDir attribute in tsconfig and using the gulp.dest.
  • On my linux machine (ubuntu 16.04) the import replacement makes some mistakes:
    • There is a syntax error causes by a double "/"
      • tsconfig: .."@backend-TP*": ["./platform/TP/*"]..
      • src: import { CategoryTraceListener } from '@backend-TP/shared/diagnostics';
      • generated: const diagnostics_1 = require("./platform/TP//shared/diagnostics");
    • My current workaround in replace-path.js line = line.replace(new RegExp(tscpath+"/", "g"), "./" + relativePath + "/");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment