Maintain src/ folder structure when building to dist/ folder with TypeScript 3
Asked Answered
L

12

118

I have a TypeScript nodejs server with this structure:

tsconfig.json
package.json
src/
    middleware/
    utils/
    index.ts
dist/
    middleware/
    utils/
    index.js

When using TypeScript 2, I was able to transpile my project from the src/ to a dist/ folder and have a mirror image of my directory structure to work with.

With the release of TypeScript 3, they have introduced project references and changed the way code is transpiled into an output directory. Now tsc outputs to the dist/ folder in a nested way like this:

dist/
    src/
        middleware/
        utils/
        index.js

My tsconfig.json is:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "allowJs": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "resolveJsonModule": true,
    "declaration": false,
    "outDir": "dist/",
    "lib": [
      "es7",
      "dom"
    ]
  },
  "include": [
    "src/"
  ]
}

How can I configure TypeScript to output my src/ folder as a mirror image into a dist/ folder?

Luciennelucier answered 31/8, 2018 at 19:35 Comment(0)
M
130

I had a similar problem when initially converting to a TypeScript project. I also set resolveJsonModule: true and the src directory was copied to the output dist directory.

The underlying reason is that one of my source files required package.json at the root of the project. Once I removed that, tsc no longer added src to the dist directory.

In short, make sure you are not requiring files outside of your src directory.

Explanatory FAQ here: https://github.com/Microsoft/TypeScript/wiki/FAQ#why-does---outdir-moves-output-after-adding-a-new-file

Malaspina answered 19/11, 2019 at 19:46 Comment(6)
It works! But why? Why does resolveJsonModule make tsc output to /dist/src instead of /dist ? It doesn't make any sense.Tachymetry
@Tachymetry because it enables the importing package.json (a "JsonModule"), and that forces rootDir to automatically get set to the directory that contains all the source (i.e. including package.json), and now the src dir is no longer the rootDir but a subdir, and so reflected in the output. See https://mcmap.net/q/188979/-39-package-json-39-is-not-under-39-rootdir-39 for more info and links to what Typescript's bossman says about it.Weld
thanks for this. it also produces the same output when you want to have a structure such as ./src/ and ./typings but wish not to have ./src in your ./dist ... long story short, as long as you reference ./typings in ./src, it will be included and so ./src will be kept. T_TCheshvan
In my case it was "include": ["**/*.ts"] -> "include": ["src/**/*.ts"] in the tsconfig.json.Predecease
You might also be able to solve your problem by using the require syntax over import. In my case I was importing a service-account.json, and changing the import to require allowed my ts build to output correctly.Hartal
In my case I had to add the migrations folder to be excluded in the exclude array within tsconfig.json..migrations folder had all the database related ALTER table migration scriptsTelescope
H
74

The structure of the output directory is controlled by the rootDir of the compilerOptions. See documentation here, setting it to ./src should solve the issue.

{
  "compilerOptions": {
    "rootDir": "src",
    ...
  },
  "include": [
    "src/"
  ]
}
Henrietta answered 20/4, 2020 at 11:46 Comment(3)
Actually it will just swap problems in this case. The OP is importing package.json, so if you change the rootDir to src, you'll get the right outDir structure, but a compilation error because you have source outside of rootDir. See https://mcmap.net/q/188979/-39-package-json-39-is-not-under-39-rootdir-39 for more info and links to what Typescript's bossman says about it.Weld
using rootDir solved the issue for me with a local .ts library I was importingDistributee
i get Inigos mentioned issue - fix on src not in dist anymore, but a compile issue :o(Roque
T
24

The upgrade from TypeScript 2 to 3 by itself shouldn't have changed the behavior; if we can confirm that it did, that may be a bug. In any case, check that the rootDir compiler option points to your src directory and not to the parent directory, because the structure under the rootDir is what is mirrored under the outDir.

Trophoplasm answered 31/8, 2018 at 21:57 Comment(4)
I've added my tsconfig.json to help clarify. The project is configured around using the "include" key to specify the src/ directory. I just confirmed that the Typescript 2 compiler will simply mirror src/ into dist/ with this configuration, but the Typescript 3 compiler will automatically include the package.json and the src/ folder nested with dist/. Attempts to point rootDir at src/ fail because the package.json file isn't in there.Luciennelucier
I wasn't able to reproduce this behavior based on the information you've provided. If you can publish a repository that reproduces the problem, I will look. Otherwise, I can only suggest that you try deleting things from your project until the problem goes away and then you'll see what's causing it.Trophoplasm
I was able to determine the cause. It seems that adding the resolveJsonModule: true to my tsconfig.json was causing tsc to output the dist/ directory differently. I'm still not entirely clear on why it does that, but it does seem to be a talking point in a few Github issues: github.com/Microsoft/TypeScript/issues/25216 and github.com/Microsoft/TypeScript/issues/24744 Thank you for your help Matt!Luciennelucier
This is not at all clear from the compiler-options page.Deputation
S
21

In addition to specifying compilerOptions.outDir, specify compilerOptions.rootDir in tsconfig.json.

{
  "compilerOptions": {
     // ...
    "outDir": "dist",
    "rootDir": "./",
    // ...
  }
}

Then run: $ tsc -b inside the folder where the tsconfig.json file is.

Note: the compilerOptions.rootDir should be used when you wish include a structure of files of an non-nested folder in the folder of tsconfig.json file.

Seeder answered 7/4, 2021 at 16:20 Comment(5)
What does the -b flag do? Can't find docs --build and --baseUrl as in there, but no --bRoque
Sorry for late. The -b flag is a alias to --build flag.Seeder
Thanks for this! it works. You could also set the "composite": true option in tsconfig.json instead of using the -b command line flag.Weiss
I didn't know that. I'll try it. Thanks. Just run the tsc command in this case?Seeder
@CraigWayne sorry, but that doesn't work properly. The -b flag is necessary when we use line command.Seeder
L
5

I've used a symlink to accomplish this. It neatly allows you to reference root-level files without referencing them directly. For example:

  1. From /src, create a link to package.json:
ln -s ../package.json ./details.json
  1. Refer to details.json in your TypeScript file:
import { version } from './details.json';

exports.handler = async function ( event: Event ) {
  console.log( `lambda version v${version}` );
  1. Bask in the grandeur of dist's flattened file structure:
$ tsc

$ tree dist 
dist
├── index.d.ts
├── index.js
└── details.json

0 directories, 3 files
Lowdown answered 8/3, 2022 at 20:46 Comment(0)
H
1

If you're trying to compile a typescript file at /scr/mydir/hello.ts to /dist/mydir/hello.js but the file keeps getting created at /dist/hello.js, what you can do is to add another typescript file at /src/another.ts. That way the two compiled files will go to /src/another.js and /src/mydir/hello.js. Rememver, in your tsconfig.json, outDir must be set to ./dist

Hitormiss answered 17/1, 2022 at 9:12 Comment(0)
S
1

In case you have multiple entries under the include option, make sure they are resolved.

"include": ["src", "tests"],

For example, if tests is not found, the src directory will not be present in the outDir.

Suzysuzzy answered 23/5, 2022 at 17:48 Comment(0)
N
0

I believe that including one more folder, such as spec with test files would resolve the issue as well. This does not respond the original question, but I found it interesting to mention in the context.

Nobleminded answered 9/2, 2023 at 20:5 Comment(0)
M
0

and also enable allowJs property, setting it to true. Then, all files others .js files is copied, replicating all structure of src dir to dist dir.

https://www.typescriptlang.org/tsconfig/#allowJs

Melodrama answered 24/11, 2023 at 13:21 Comment(0)
A
0

I had the same problem recently. In the tsconfig.json file, you need to specify the output directory, for instance "outDir": "./dist",. The reason you have several folders in the dist folder is because you have two folders in the root which are compile and pasted in the dist folder. You can specify in the tsconfig.json "rootDir": "./src" thereafter only src folder will be considered.

Avant answered 20/2 at 17:42 Comment(0)
Z
0

set the "outDir": "./dist", in tsconfig.json

Zielsdorf answered 21/2 at 17:22 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Dominant
G
-2

you can change file import from src/entities/Post -> ../entities/Post in file in ./src

this changes the import in the dist folder.

Gainer answered 31/3, 2021 at 18:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.