Skip to content
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

TS5055 error while import a non relative json module with resolveJsonModule option #24715

Closed
grayflow opened this issue Jun 6, 2018 · 31 comments
Labels
Fixed A PR has been merged for this issue Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@grayflow
Copy link

grayflow commented Jun 6, 2018

TypeScript Version: 3.0.0-dev.20180605

Search Terms: TS5055 resolveJsonModule

Code

tsjson> find .
.
./main.ts
./json
./json/myjson.json
./tsconfig.json
./src
./src/test.ts

tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "module": "es2015",
    "moduleResolution": "node",
    "baseUrl": "./",

    "resolveJsonModule": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,


    "strict": true,
    "noEmitOnError": true
  },
  "include": [
    "main.ts",
    "src",
    "json"
  ],
  "exclude": [
    "node_modules"
  ]
}

main.ts:

import "test";

src/test.ts:

import myjson from "json/myjson.json";

console.log('hello world!', myjson.message);
export {}

json/myjson.json:

{
    "message": "to be continue..."
}

Expected behavior:
compile successful

Actual behavior:
tsjson> tsc
error TS5055: Cannot write file '*************/tsjson/json/myjson.json' because it would overwrite input file.

Playground Link:

Related Issues:

@mhegazy
Copy link
Contributor

mhegazy commented Jun 6, 2018

the compiler when resolving a .json file will read it and write it again. so you really want to have --outDir option set to avoid the compiler overwriting you input file.

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jun 6, 2018
@ezolenko
Copy link

ezolenko commented Jun 6, 2018

In this case the error pops out when rollup plugin calls ts.parseConfigFileTextToJson() -- not when typescript is trying to overwrite the file -- in fact typescript won't be doing any file writes at all, all transpiled code is getting fed to rollup.

I will do a workaround by providing a fake outDir value, but the check probably doesn't belong in parseConfigFileTextToJson.

@jpike88
Copy link

jpike88 commented Jun 7, 2018

@mhegazy If there is no outDir specified, why should the .json file be duplicated? It's a static resource... is there a way to do this without needing outDir?

@jpike88
Copy link

jpike88 commented Jun 7, 2018

#24743

@grayflow
Copy link
Author

grayflow commented Jun 7, 2018

@mhegazy, still not feel right: if import a native js module, it won't issue TS5055 error

@grayflow
Copy link
Author

grayflow commented Jun 7, 2018

maybe add an compile option --allowJson(and default to false) like --allowJs for js file?

@mhegazy
Copy link
Contributor

mhegazy commented Jun 7, 2018

still not feel right: if import a native js module, it won't issue TS5055 error

cause the compiler does not overwrite .d.ts files. so no issue here.

maybe add an compile option --allowJson(and default to false) like --allowJs for js file?

if you use --allowJs you will get the same error. once the compiler tries to write a file in the same locations a source file an error is issued. This guarantees there are no user data loss caused by the compiler overwriting an existing file.

@grayflow
Copy link
Author

grayflow commented Jun 9, 2018

yes , import js module and set --allowJs to true would cause TS5055 too. if we know the imported js file do not need to be transformed(compiled), we would set allowJs to false, and i think that is the point to provide allowJs option. json file/module would never need to be transformed, so why not just make them "no emit" by default (and we don't lose anything)?

@mhegazy
Copy link
Contributor

mhegazy commented Jun 11, 2018

if we know the imported js file do not need to be transformed(compiled)

well we do not rely know that.

@ezolenko
Copy link

And this is why ts.parseConfigFileTextToJson() might be a wrong place for the check :)

@jpike88
Copy link

jpike88 commented Jun 12, 2018

@mhegazy

the compiler when resolving a .json file will read it and write it again

If the outDir is different, that makes sense. But if not, then why try to overwrite it? .json files are closer to being treated like static assets than javascript, so there isn't a 'build artefact' equivalent here.

@impacmp
Copy link

impacmp commented Jun 14, 2018

this issue should be solved since it makes sence to use "./" as outDir in some cases

@jpike88
Copy link

jpike88 commented Jun 19, 2018

@mhegazy why is this issue still marked 'working as intended'?

If this is intended to break all projects that don't specify outDir, then how does that make any sense?

@jpike88
Copy link

jpike88 commented Jun 19, 2018

And can you answer why the compiler is attempting to write a static file over the top of itself?

The correct solution here is to not attempt to overwrite a .json file is outDir is not specified, because the default location will be in the same directory. Seems like a pretty simple solution to me.

@jpike88
Copy link

jpike88 commented Jun 19, 2018

My actual building of the code involves a special outDir, so thankfully this isn't interfering with my deployment.

However this issue is breaking checkers which are just concerned with ensuring the code is all good and nothing more.

fuse-box/fuse-box-typechecker#53

I have proposed a PR to the a particular checker that essentially ignores all TS5055 checks as a workaround. I don't think this is a good idea, it makes sense for TS to be smarter about this.

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@MarkTiedemann
Copy link

MarkTiedemann commented Jul 24, 2018

Can this be re-opened and the Working as Intended label get removed?

If it is really "working as intended", I think there should be some documentation that this feature only works in conjunction with the outDir option.

It almost seems like it is not intended to be used for common use-cases like:

import { version } from './package.json'

I guess it would be fine if you could somehow ignore TS5055, but // @ts-ignore has no power here so people using bare-bones tsc are out of luck...

@MarkTiedemann
Copy link

Another common use-case.

Let's say I have the following project structure:

package.json
src/*.ts
dist/*.js

If I specify include: src, outDir: dist and resolveJsonModule: true, and import the package.json version with import { version } from '../package.json', then suddenly my dist directory looks like this:

dist/package.json
dist/src/*.js

Even if that's "working as intended", I think that might surprise a lot of people.

@kasperisager
Copy link

kasperisager commented Oct 5, 2018

Just hit this as well. The fact that the outDir option has to be set for resolveJsonModule to work properly seems like a hack. My use case is a JSON file containing test fixtures which is imported from a test suite. Now my choice is to either output test/ to something like dist-test/ (as src/ would have to be output to dist/) or simply disable well-typed JSON imports, and I'm a little bummed out about the latter being preferable.

@gchamon
Copy link

gchamon commented Nov 6, 2018

we should be able to tell tsc to skip outputting json files when nedded with "exclude": "folderWithJson/*"

@gchamon
Copy link

gchamon commented Nov 6, 2018

so what I did was compile to .tmp and move files to dist to achieve the desired result of excluding folders with json from typescript compilation.

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": ".tmp",
    "paths": {
      "@static/*": ["static/*"],
      // ...
      "@controller/*": ["src/controller/*"]
    }
  }
}

package.json:

{
  "_moduleAliases": {
    "@static": "static",
    // ...
    "@controller": "dist/controller"
  },
  // ...
  "scripts": {
    "build": "rm -rf dist/*; tsc; mv .tmp/src/* dist;"
  }
}

this way relative imports and express statics are preserved as well as all masks (from paths or _moduleAliases)

@oryandunn
Copy link

we should be able to tell tsc to skip outputting json files when nedded with "exclude": "folderWithJson/*"

I was surprised to find this doesn't work already. I've had to revert to using require instead of import to load a json due to this bug. I can't have the json copied to the outDir as it's not under my rootDir in the project, it changes the outDir structure as @MarkTiedemann shows above, and I get a TS6059 error.

When using include in tsconfig.json, if the json file is not explicitly included with include, or is explicitly listed in exclude, the json should not be copied to outDir.

@gchamon
Copy link

gchamon commented Nov 9, 2018

Have you tried my method of outputting to a temporary folder and having npm copy contents of .tmp/src to dist?

@oryandunn
Copy link

oryandunn commented Nov 9, 2018

Have you tried my method of outputting to a temporary folder and having npm copy contents of .tmp/src to dist?

I'm sure that would work for the normal build case, but I don't think it'll work when tsc is in watch mode, which I use. Ultimately, resolveJsonModule should respect the include/exclude directives.

@oryandunn
Copy link

Before I found this issue, I also left a comment on #24744 which is still open (I hadn't realized this issue is closed and marked fixed, so this discussion will likely go unnoticed).

@gchamon
Copy link

gchamon commented Nov 10, 2018

You could use npm-watch for frontend compilation and nodemon for node apps

@NickIliev
Copy link

Having to explicitly set one option like outDir to enable other option like resolveJsonModule is not (in my opinion) something that should be marked as working as intended. There are many scenarios where, you can't have or do not want to have different outDir. For example in NativeScript the outDir is exactly the same which is resulting in that resolveJsonModule to be unusable with the latest TypeScript version.

I thing that the options should be decoupled - we shouldn't have to mandatory set one option to have another in a working state. Not to mention that you can still set the outDir` to the very same folder and cause the very same bug to reappear (which is creating a third rule - do not set outDir as the project dir...)

@aminnairi
Copy link

aminnairi commented Mar 22, 2019

I'm using webpack.config.ts and I would have loved to have this feature to read the dependencies keys of my package.json. But for now, the little hack that I'm using is to read the file using Node's tools. Yeah I know not very intuitive and hacky but it is working.

'use strict';
import { readFileSync } from 'fs';
import { resolve } from 'path'; 
export default {
  // ...
  externals: Object.keys(JSON.parse(readFileSync(resolve('package.json')).toString()).dependencies),
  // ...
};

@linxiaowu66
Copy link

Another common use-case.

Let's say I have the following project structure:

package.json
src/*.ts
dist/*.js

If I specify include: src, outDir: dist and resolveJsonModule: true, and import the package.json version with import { version } from '../package.json', then suddenly my dist directory looks like this:

dist/package.json
dist/src/*.js

Even if that's "working as intended", I think that might surprise a lot of people.

This issue has any updates ? or workaround?

@santiagohdzb
Copy link

santiagohdzb commented Jun 6, 2019

this issue should not be closed as there is still people struggling with this. Is not fixed and while working with visual studio is very annoying

@MaximDevoir
Copy link

MaximDevoir commented Oct 16, 2019

If you follow this common use-case, then I have a workaround for importing package.json without mangling the output directory.

I am able to convert this problematic statement:

import pkg from '../package.json'

into

const pkg = require('../package.json')

Previously, I had used require(require.resolve('../package.json')). I have now found that extra call to be unnecessary. I don't remember why we needed require.resolve, but that at the time our program made some complaints.

One side-effect is you lose access to static type-checking as the compiler doesn't know where the dynamically imported module is from at compile-time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fixed A PR has been merged for this issue Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests