"github.com/gohugoio/hugo/htesting"
 
+       "github.com/spf13/afero"
        "github.com/spf13/viper"
 
        qt "github.com/frankban/quicktest"
   "scripts": {},
 
   "dependencies": {
-    "to-camel-case": "1.0.0"
+               "to-camel-case": "1.0.0",
+               "react": "^16",
+               "react-dom": "^16"
   }
 }
 `
 `)
 
 }
+
+func TestJSBuildGlobals(t *testing.T) {
+       if !isCI() {
+               t.Skip("skip (relative) long running modules test when running locally")
+       }
+
+       wd, _ := os.Getwd()
+       defer func() {
+               os.Chdir(wd)
+       }()
+
+       c := qt.New(t)
+
+       workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-test-js")
+       c.Assert(err, qt.IsNil)
+       defer clean()
+
+       v := viper.New()
+       v.Set("workingDir", workDir)
+       v.Set("disableKinds", []string{"taxonomy", "term", "page"})
+       b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger())
+
+       b.Fs = hugofs.NewDefault(v)
+       b.WithWorkingDir(workDir)
+       b.WithViper(v)
+       b.WithContent("p1.md", "")
+
+       jsDir := filepath.Join(workDir, "assets", "js")
+       b.Assert(os.MkdirAll(jsDir, 0777), qt.IsNil)
+       b.Assert(os.Chdir(workDir), qt.IsNil)
+
+       b.WithTemplates("index.html", `
+{{- $js := resources.Get "js/main-project.js" | js.Build -}}
+{{ template "print" (dict "js" $js "name" "root") }}
+
+{{- define "print" -}}
+{{ printf "rellink-%s-%s" .name .js.RelPermalink | safeHTML }}
+{{ printf "mime-%s-%s" .name .js.MediaType | safeHTML }}
+{{ printf "content-%s-%s" .name .js.Content | safeHTML }}
+{{- end -}}
+`)
+
+       b.WithSourceFile("assets/js/normal.js", `
+const name = "root-normal";
+export default name;
+`)
+       b.WithSourceFile("assets/js/main-project.js", `
+import normal from "@js/normal";
+window.normal = normal; // make sure not to tree-shake
+`)
+
+       b.Build(BuildCfg{})
+
+       b.AssertFileContent("public/index.html", `
+const name = "root-normal";
+`)
+}
+
+func TestJSBuildOverride(t *testing.T) {
+       if !isCI() {
+               t.Skip("skip (relative) long running modules test when running locally")
+       }
+
+       wd, _ := os.Getwd()
+       defer func() {
+               os.Chdir(wd)
+       }()
+
+       c := qt.New(t)
+
+       workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-test-js2")
+       c.Assert(err, qt.IsNil)
+       defer clean()
+       // workDir := "/tmp/hugo-test-js2"
+       c.Assert(os.Chdir(workDir), qt.IsNil)
+
+       cfg := viper.New()
+       cfg.Set("workingDir", workDir)
+       fs := hugofs.NewFrom(afero.NewOsFs(), cfg)
+
+       b := newTestSitesBuilder(t)
+       b.Fs = fs
+       b.WithLogger(loggers.NewWarningLogger())
+
+       realWrite := func(name string, content string) {
+               realLocation := filepath.Join(workDir, name)
+               realDir := filepath.Dir(realLocation)
+               if _, err := os.Stat(realDir); err != nil {
+                       os.MkdirAll(realDir, 0777)
+               }
+               bytesContent := []byte(content)
+               // c.Assert(ioutil.WriteFile(realLocation, bytesContent, 0777), qt.IsNil)
+               c.Assert(afero.WriteFile(b.Fs.Source, realLocation, bytesContent, 0777), qt.IsNil)
+       }
+
+       realWrite("config.toml", `
+baseURL="https://example.org"
+
+[module]
+[[module.imports]]
+path="mod2"
+[[module.imports.mounts]]
+source="assets"
+target="assets"
+[[module.imports.mounts]]
+source="layouts"
+target="layouts"
+[[module.imports]]
+path="mod1"
+[[module.imports.mounts]]
+source="assets"
+target="assets"
+[[module.imports.mounts]]
+source="layouts"
+target="layouts"
+`)
+
+       realWrite("content/p1.md", `---
+layout: sample
+---
+`)
+       realWrite("themes/mod1/layouts/_default/sample.html", `
+{{- $js := resources.Get "js/main-project.js" | js.Build -}}
+{{ template "print" (dict "js" $js "name" "root") }}
+
+{{- $js = resources.Get "js/main-mod1.js" | js.Build -}}
+{{ template "print" (dict "js" $js "name" "mod1") }}
+
+{{- $js = resources.Get "js/main-mod2.js" | js.Build (dict "data" .Site.Params) -}}
+{{ template "print" (dict "js" $js "name" "mod2") }}
+
+{{- $js = resources.Get "js/main-mod2.js" | js.Build (dict "data" .Site.Params "sourceMap" "inline" "targetPath" "js/main-mod2-inline.js") -}}
+{{ template "print" (dict "js" $js "name" "mod2") }}
+
+{{- $js = resources.Get "js/main-mod2.js" | js.Build (dict "data" .Site.Params "sourceMap" "external" "targetPath" "js/main-mod2-external.js") -}}
+{{ template "print" (dict "js" $js "name" "mod2") }}
+
+{{- define "print" -}}
+{{ printf "rellink-%s-%s" .name .js.RelPermalink | safeHTML }}
+{{ printf "mime-%s-%s" .name .js.MediaType | safeHTML }}
+{{ printf "content-%s-%s" .name .js.Content | safeHTML }}
+{{- end -}}
+`)
+
+       // Override project included file
+       // This file will override the one in mod1 and mod2
+       realWrite("assets/js/override.js", `
+const name = "root-override";
+export default name;
+`)
+
+       // Add empty theme mod config files
+       realWrite("themes/mod1/config.yml", ``)
+       realWrite("themes/mod2/config.yml", ``)
+
+       // This is the main project js file.
+       // try to include @js/override which is overridden inside of project
+       // try to include @js/override-mod which is overridden in mod2
+       realWrite("assets/js/main-project.js", `
+import override from "@js/override";
+import overrideMod from "@js/override-mod";
+window.override = override; // make sure to prevent tree-shake
+window.overrideMod  = overrideMod; // make sure to prevent tree-shake
+`)
+       // This is the mod1 js file
+       // try to include @js/override which is overridden inside of the project
+       // try to include @js/override-mod which is overridden in mod2
+       realWrite("themes/mod1/assets/js/main-mod1.js", `
+import override from "@js/override";
+import overrideMod from "@js/override-mod";
+window.mod = "mod1";
+window.override = override; // make sure to prevent tree-shake
+window.overrideMod  = overrideMod; // make sure to prevent tree-shake
+`)
+       // This is the mod1 js file (overridden in mod2)
+       // try to include @js/override which is overridden inside of the project
+       // try to include @js/override-mod which is overridden in mod2
+       realWrite("themes/mod2/assets/js/main-mod1.js", `
+import override from "@js/override";
+import overrideMod from "@js/override-mod";
+window.mod = "mod2";
+window.override = override; // make sure to prevent tree-shake
+window.overrideMod  = overrideMod; // make sure to prevent tree-shake
+`)
+       // This is mod2 js file
+       // try to include @js/override which is overridden inside of the project
+       // try to include @js/override-mod which is overridden in mod2
+       // try to include @config which is declared in a local jsconfig.json file
+       // try to include @data which was passed as "data" into js.Build
+       realWrite("themes/mod2/assets/js/main-mod2.js", `
+import override from "@js/override";
+import overrideMod from "@js/override-mod";
+import config from "@config";
+import data from "@data";
+window.data = data;
+window.override = override; // make sure to prevent tree-shake
+window.overrideMod  = overrideMod; // make sure to prevent tree-shake
+window.config = config;
+`)
+       realWrite("themes/mod2/assets/js/jsconfig.json", `
+{
+       "compilerOptions": {
+               "baseUrl": ".",
+               "paths": {
+                       "@config": ["./config.json"]
+               }
+       }
+}
+`)
+       realWrite("themes/mod2/assets/js/config.json", `
+{
+       "data": {
+               "sample": "sample"
+       }
+}
+`)
+       realWrite("themes/mod1/assets/js/override.js", `
+const name = "mod1-override";
+export default name;
+`)
+       realWrite("themes/mod2/assets/js/override.js", `
+const name = "mod2-override";
+export default name;
+`)
+       realWrite("themes/mod1/assets/js/override-mod.js", `
+const nameMod = "mod1-override";
+export default nameMod;
+`)
+       realWrite("themes/mod2/assets/js/override-mod.js", `
+const nameMod = "mod2-override";
+export default nameMod;
+`)
+       b.WithConfigFile("toml", `
+baseURL="https://example.org"
+themesDir="./themes"
+[module]
+[[module.imports]]
+path="mod2"
+[[module.imports.mounts]]
+source="assets"
+target="assets"
+[[module.imports.mounts]]
+source="layouts"
+target="layouts"
+[[module.imports]]
+path="mod1"
+[[module.imports.mounts]]
+source="assets"
+target="assets"
+[[module.imports.mounts]]
+source="layouts"
+target="layouts"
+`)
+
+       b.WithWorkingDir(workDir)
+       b.LoadConfig()
+
+       b.Build(BuildCfg{})
+
+       b.AssertFileContent("public/js/main-mod1.js", `
+name = "root-override";
+nameMod = "mod2-override";
+window.mod = "mod2";
+`)
+       b.AssertFileContent("public/js/main-mod2.js", `
+name = "root-override";
+nameMod = "mod2-override";
+sample: "sample"
+"sect"
+`)
+       b.AssertFileContent("public/js/main-project.js", `
+name = "root-override";
+nameMod = "mod2-override";
+`)
+       b.AssertFileContent("public/js/main-mod2-external.js.map", `
+const nameMod = \"mod2-override\";\nexport default nameMod;\n
+"\nimport override from \"@js/override\";\nimport overrideMod from \"@js/override-mod\";\nimport config from \"@config\";\nimport data from \"@data\";\nwindow.data = data;\nwindow.override = override; // make sure to prevent tree-shake\nwindow.overrideMod  = overrideMod; // make sure to prevent tree-shake\nwindow.config = config;\n"
+`)
+       b.AssertFileContent("public/js/main-mod2-inline.js", `
+       sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiYXNzZXRzL2pzL292ZXJyaWRlLmpzIiwgInRoZW
+`)
+}
 
 package js
 
 import (
+       "encoding/json"
        "fmt"
        "io/ioutil"
+       "os"
        "path"
+       "path/filepath"
+       "reflect"
        "strings"
 
+       "github.com/achiku/varfmt"
        "github.com/spf13/cast"
 
        "github.com/gohugoio/hugo/helpers"
        "github.com/gohugoio/hugo/resources/resource"
 )
 
+// Options esbuild configuration
 type Options struct {
        // If not set, the source path will be used as the base target path.
        // Note that the target path's extension may change if the target MIME type
        // Whether to minify to output.
        Minify bool
 
-       // Whether to write mapfiles (currently inline only)
+       // Whether to write mapfiles
        SourceMap string
 
        // The language target.
        // User defined symbols.
        Defines map[string]interface{}
 
+       // User defined data (must be JSON marshall'able)
+       Data interface{}
+
        // What to use instead of React.createElement.
        JSXFactory string
 
        contents   string
        sourcefile string
        resolveDir string
+       workDir    string
+       tsConfig   string
 }
 
 func decodeOptions(m map[string]interface{}) (Options, error) {
        return opts, nil
 }
 
+// Client context for esbuild
 type Client struct {
        rs  *resources.Spec
        sfs *filesystems.SourceFilesystem
 }
 
+// New create new client context
 func New(fs *filesystems.SourceFilesystem, rs *resources.Spec) *Client {
        return &Client{rs: rs, sfs: fs}
 }
        return internal.NewResourceTransformationKey("jsbuild", t.optsm)
 }
 
+func appendExts(list []string, rel string) []string {
+       for _, ext := range []string{".tsx", ".ts", ".jsx", ".mjs", ".cjs", ".js", ".json"} {
+               list = append(list, fmt.Sprintf("%s/index%s", rel, ext))
+       }
+       return list
+}
+
 func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx) error {
        ctx.OutMediaType = media.JavascriptType
 
                return err
        }
 
-       sdir, sfile := path.Split(ctx.SourcePath)
+       sdir, sfile := filepath.Split(t.sfs.RealFilename(ctx.SourcePath))
+       opts.workDir, err = filepath.Abs(t.rs.WorkingDir)
+       if err != nil {
+               return err
+       }
+
        opts.sourcefile = sfile
-       opts.resolveDir = t.sfs.RealFilename(sdir)
+       opts.resolveDir = sdir
        opts.contents = string(src)
        opts.mediaType = ctx.InMediaType
 
+       // Create new temporary tsconfig file
+       newTSConfig, err := ioutil.TempFile("", "tsconfig.*.json")
+       if err != nil {
+               return err
+       }
+
+       filesToDelete := make([]*os.File, 0)
+
+       defer func() {
+               for _, file := range filesToDelete {
+                       os.Remove(file.Name())
+               }
+       }()
+
+       filesToDelete = append(filesToDelete, newTSConfig)
+       configDir, _ := filepath.Split(newTSConfig.Name())
+
+       // Search for the innerMost tsconfig or jsconfig
+       innerTsConfig := ""
+       tsDir := opts.resolveDir
+       baseURLAbs := configDir
+       baseURL := "."
+       for tsDir != "." {
+               tryTsConfig := path.Join(tsDir, "tsconfig.json")
+               _, err := os.Stat(tryTsConfig)
+               if err != nil {
+                       tryTsConfig := path.Join(tsDir, "jsconfig.json")
+                       _, err = os.Stat(tryTsConfig)
+                       if err == nil {
+                               innerTsConfig = tryTsConfig
+                               baseURLAbs = tsDir
+                               break
+                       }
+               } else {
+                       innerTsConfig = tryTsConfig
+                       baseURLAbs = tsDir
+                       break
+               }
+               if tsDir == opts.workDir {
+                       break
+               }
+               tsDir = path.Dir(tsDir)
+       }
+
+       // Resolve paths for @assets and @js (@js is just an alias for assets/js)
+       dirs := make([]string, 0)
+       rootPaths := make([]string, 0)
+       for _, dir := range t.sfs.RealDirs(".") {
+               rootDir := dir
+               if !strings.HasSuffix(dir, "package.json") {
+                       dirs = append(dirs, dir)
+               } else {
+                       rootDir, _ = path.Split(dir)
+               }
+               nodeModules := path.Join(rootDir, "node_modules")
+               if _, err := os.Stat(nodeModules); err == nil {
+                       rootPaths = append(rootPaths, nodeModules)
+               }
+       }
+
+       // Construct new temporary tsconfig file content
+       config := make(map[string]interface{})
+       if innerTsConfig != "" {
+               oldConfig, err := ioutil.ReadFile(innerTsConfig)
+               if err == nil {
+                       // If there is an error, it just means there is no config file here.
+                       // Since we're also using the tsConfig file path to detect where
+                       // to put the temp file, this is ok.
+                       err = json.Unmarshal(oldConfig, &config)
+                       if err != nil {
+                               return err
+                       }
+               }
+       }
+
+       if config["compilerOptions"] == nil {
+               config["compilerOptions"] = map[string]interface{}{}
+       }
+
+       // Assign new global paths to the config file while reading existing ones.
+       compilerOptions := config["compilerOptions"].(map[string]interface{})
+
+       // Handle original baseUrl if it's there
+       if compilerOptions["baseUrl"] != nil {
+               baseURL = compilerOptions["baseUrl"].(string)
+               oldBaseURLAbs := path.Join(tsDir, baseURL)
+               rel, _ := filepath.Rel(configDir, oldBaseURLAbs)
+               configDir = oldBaseURLAbs
+               baseURLAbs = configDir
+               if "/" != helpers.FilePathSeparator {
+                       // On windows we need to use slashes instead of backslash
+                       rel = strings.ReplaceAll(rel, helpers.FilePathSeparator, "/")
+               }
+               if rel != "" {
+                       if strings.HasPrefix(rel, ".") {
+                               baseURL = rel
+                       } else {
+                               baseURL = fmt.Sprintf("./%s", rel)
+                       }
+               }
+               compilerOptions["baseUrl"] = baseURL
+       } else {
+               compilerOptions["baseUrl"] = baseURL
+       }
+
+       jsRel := func(refPath string) string {
+               rel, _ := filepath.Rel(configDir, refPath)
+               if "/" != helpers.FilePathSeparator {
+                       // On windows we need to use slashes instead of backslash
+                       rel = strings.ReplaceAll(rel, helpers.FilePathSeparator, "/")
+               }
+               if rel != "" {
+                       if !strings.HasPrefix(rel, ".") {
+                               rel = fmt.Sprintf("./%s", rel)
+                       }
+               } else {
+                       rel = "."
+               }
+               return rel
+       }
+
+       // Handle possible extends
+       if config["extends"] != nil {
+               extends := config["extends"].(string)
+               extendsAbs := path.Join(tsDir, extends)
+               rel := jsRel(extendsAbs)
+               config["extends"] = rel
+       }
+
+       var optionsPaths map[string]interface{}
+       // Get original paths if they exist
+       if compilerOptions["paths"] != nil {
+               optionsPaths = compilerOptions["paths"].(map[string]interface{})
+       } else {
+               optionsPaths = make(map[string]interface{})
+       }
+       compilerOptions["paths"] = optionsPaths
+
+       assets := make([]string, 0)
+       assetsExact := make([]string, 0)
+       js := make([]string, 0)
+       jsExact := make([]string, 0)
+       for _, dir := range dirs {
+               rel := jsRel(dir)
+               assets = append(assets, fmt.Sprintf("%s/*", rel))
+               assetsExact = appendExts(assetsExact, rel)
+
+               rel = jsRel(filepath.Join(dir, "js"))
+               js = append(js, fmt.Sprintf("%s/*", rel))
+               jsExact = appendExts(jsExact, rel)
+       }
+
+       optionsPaths["@assets/*"] = assets
+       optionsPaths["@js/*"] = js
+
+       // Make @js and @assets absolue matches search for index files
+       // to get around the problem in ESBuild resolving folders as index files.
+       optionsPaths["@assets"] = assetsExact
+       optionsPaths["@js"] = jsExact
+
+       var newDataFile *os.File
+       if opts.Data != nil {
+               // Create a data file
+               lines := make([]string, 0)
+               lines = append(lines, "// auto generated data import")
+               exports := make([]string, 0)
+               keys := make(map[string]bool)
+
+               var bytes []byte
+
+               conv := reflect.ValueOf(opts.Data)
+               convType := conv.Kind()
+               if convType == reflect.Interface {
+                       if conv.IsNil() {
+                               conv = reflect.Value{}
+                       }
+               }
+
+               if conv.Kind() != reflect.Map {
+                       // Write out as single JSON file
+                       newDataFile, err = ioutil.TempFile("", "data.*.json")
+                       // Output the data
+                       bytes, err = json.MarshalIndent(conv.InterfaceData(), "", "  ")
+                       if err != nil {
+                               return err
+                       }
+               } else {
+                       // Try to allow tree shaking at the root
+                       newDataFile, err = ioutil.TempFile(configDir, "data.*.js")
+                       for _, key := range conv.MapKeys() {
+                               strKey := key.Interface().(string)
+                               if keys[strKey] {
+                                       continue
+                               }
+                               keys[strKey] = true
+
+                               value := conv.MapIndex(key)
+
+                               keyVar := varfmt.PublicVarName(strKey)
+
+                               // Output the data
+                               bytes, err := json.MarshalIndent(value.Interface(), "", "  ")
+                               if err != nil {
+                                       return err
+                               }
+                               jsonValue := string(bytes)
+
+                               lines = append(lines, fmt.Sprintf("export const %s = %s;", keyVar, jsonValue))
+                               exports = append(exports, fmt.Sprintf("  %s,", keyVar))
+                               if strKey != keyVar {
+                                       exports = append(exports, fmt.Sprintf("  [\"%s\"]: %s,", strKey, keyVar))
+                               }
+                       }
+
+                       lines = append(lines, "const all = {")
+                       for _, line := range exports {
+                               lines = append(lines, line)
+                       }
+                       lines = append(lines, "};")
+                       lines = append(lines, "export default all;")
+
+                       bytes = []byte(strings.Join(lines, "\n"))
+               }
+
+               // Write tsconfig file
+               _, err = newDataFile.Write(bytes)
+               if err != nil {
+                       return err
+               }
+               err = newDataFile.Close()
+               if err != nil {
+                       return err
+               }
+
+               // Link this file into `import data from "@data"`
+               dataFiles := make([]string, 1)
+               rel, _ := filepath.Rel(baseURLAbs, newDataFile.Name())
+               dataFiles[0] = rel
+               optionsPaths["@data"] = dataFiles
+
+               filesToDelete = append(filesToDelete, newDataFile)
+       }
+
+       if len(rootPaths) > 0 {
+               // This will allow import "react" to resolve a react module that's
+               // either in the root node_modules or in one of the hugo mods.
+               optionsPaths["*"] = rootPaths
+       }
+
+       // Output the new config file
+       bytes, err := json.MarshalIndent(config, "", "  ")
+       if err != nil {
+               return err
+       }
+
+       // Write tsconfig file
+       _, err = newTSConfig.Write(bytes)
+       if err != nil {
+               return err
+       }
+       err = newTSConfig.Close()
+       if err != nil {
+               return err
+       }
+
+       // Tell ESBuild about this new config file to use
+       opts.tsConfig = newTSConfig.Name()
+
        buildOptions, err := toBuildOptions(opts)
        if err != nil {
+               os.Remove(opts.tsConfig)
                return err
        }
 
        result := api.Build(buildOptions)
+
+       if len(result.Warnings) > 0 {
+               for _, value := range result.Warnings {
+                       if value.Location != nil {
+                               t.rs.Logger.WARN.Println(fmt.Sprintf("%s:%d: WARN: %s",
+                                       filepath.Join(sdir, value.Location.File),
+                                       value.Location.Line, value.Text))
+                               t.rs.Logger.WARN.Println("  ", value.Location.LineText)
+                       } else {
+                               t.rs.Logger.WARN.Println(fmt.Sprintf("%s: WARN: %s",
+                                       sdir,
+                                       value.Text))
+                       }
+               }
+       }
        if len(result.Errors) > 0 {
-               return fmt.Errorf("%s", result.Errors[0].Text)
+               output := result.Errors[0].Text
+               for _, value := range result.Errors {
+                       var line string
+                       if value.Location != nil {
+                               line = fmt.Sprintf("%s:%d ERROR: %s",
+                                       filepath.Join(sdir, value.Location.File),
+                                       value.Location.Line, value.Text)
+                       } else {
+                               line = fmt.Sprintf("%s ERROR: %s",
+                                       sdir,
+                                       value.Text)
+                       }
+                       t.rs.Logger.ERROR.Println(line)
+                       output = fmt.Sprintf("%s\n%s", output, line)
+                       if value.Location != nil {
+                               t.rs.Logger.ERROR.Println("  ", value.Location.LineText)
+                       }
+               }
+               return fmt.Errorf("%s", output)
+       }
+
+       if buildOptions.Outfile != "" {
+               _, tfile := path.Split(opts.TargetPath)
+               output := fmt.Sprintf("%s//# sourceMappingURL=%s\n",
+                       string(result.OutputFiles[1].Contents), tfile+".map")
+               _, err := ctx.To.Write([]byte(output))
+               if err != nil {
+                       return err
+               }
+               ctx.PublishSourceMap(string(result.OutputFiles[0].Contents))
+       } else {
+               ctx.To.Write(result.OutputFiles[0].Contents)
        }
-       ctx.To.Write(result.OutputFiles[0].Contents)
        return nil
 }
 
+// Process process esbuild transform
 func (c *Client) Process(res resources.ResourceTransformer, opts map[string]interface{}) (resource.Resource, error) {
        return res.Transform(
                &buildTransformation{rs: c.rs, sfs: c.sfs, optsm: opts},
        default:
                err = fmt.Errorf("unsupported script output format: %q", opts.Format)
                return
-
        }
 
        var defines map[string]string
                defines = cast.ToStringMapString(opts.Defines)
        }
 
+       // By default we only need to specify outDir and no outFile
+       var outDir = opts.outDir
+       var outFile = ""
        var sourceMap api.SourceMap
        switch opts.SourceMap {
        case "inline":
                sourceMap = api.SourceMapInline
+       case "external":
+               // When doing external sourcemaps we should specify
+               // out file and no out dir
+               sourceMap = api.SourceMapExternal
+               outFile = filepath.Join(opts.workDir, opts.TargetPath)
+               outDir = ""
        case "":
                sourceMap = api.SourceMapNone
        default:
        }
 
        buildOptions = api.BuildOptions{
-               Outfile: "",
+               Outfile: outFile,
                Bundle:  true,
 
                Target:    target,
                MinifyIdentifiers: opts.Minify,
                MinifySyntax:      opts.Minify,
 
-               Outdir:  opts.outDir,
+               Outdir:  outDir,
                Defines: defines,
 
                Externals: opts.Externals,
                JSXFactory:  opts.JSXFactory,
                JSXFragment: opts.JSXFragment,
 
-               //Tsconfig: opts.TSConfig,
+               Tsconfig: opts.tsConfig,
 
                Stdin: &api.StdinOptions{
                        Contents:   opts.contents,