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

Including .js files in input causes "error TS5055: Cannot write file '_filename.js_' because it would overwrite input file." #768

Open
cpcallen opened this issue Oct 19, 2022 · 3 comments

Comments

@cpcallen
Copy link

I'm trying to establish if tscc would be a suitable tool for building Blockly, which is currently built using tsc and Closure Compiler (running in SIMPLE_OPTIMIZATIONS mode in part due to incompatibility between tsc output for enum and Closure Compiler's prohibition on quoting property names—presumably one of the motivations for the creation of tscikle in the first place).

At the moment I have checked out our develop branch and am trying to compile our advanced compilation test (which verifies that Blockly can be built using ADVANCED_OPTIMIZATIONS) by modifying our tsconfig.json to:

{
  "include": [
    "core/**/*",
    "closure/**/*",
    "tests/compile/**/*", // Added for advanced compilation test.
  ],
  "exclude": [
    "core/blockly.js"
  ],
  "compilerOptions": {
    "allowJs": true,
    "sourceMap": true,
    "module": "ES2015",
    "moduleResolution": "node",
    "target": "ES2020",
    "strict": true,
  }
}

and added a simple tscc.spec.json:

{
  "modules": {
    "out": "tests/compile/main.js"
  },
  "prefix": "build/"
}

Unfortunately, running tscc generates errors for each .js file included in the build:

TSCC: Module option is set. tsickle converts TypeScript modules to Closure modulesvia CommonJS internally, so it will be overridden to "commonjs".
TSCC: tsickle uses a custom tslib optimized for closure compiler. importHelpers flag is set.
TS: error TS5055: Cannot write file '/Users/cpcallen/src/blockly/closure/goog/base.js' because it would overwrite input file.
error TS5055: Cannot write file '/Users/cpcallen/src/blockly/closure/goog/base_minimal.js' because it would overwrite input file.
error TS5055: Cannot write file '/Users/cpcallen/src/blockly/closure/goog/goog.js' because it would overwrite input file.
error TS5055: Cannot write file '/Users/cpcallen/src/blockly/core/main.js' because it would overwrite input file.
error TS5055: Cannot write file '/Users/cpcallen/src/blockly/tests/compile/main.js' because it would overwrite input file.
error TS5055: Cannot write file '/Users/cpcallen/src/blockly/tests/compile/main_compressed.js' because it would overwrite input file.
error TS5055: Cannot write file '/Users/cpcallen/src/blockly/tests/compile/test_blocks.js' because it would overwrite input file.
node_modules/@types/node/globals.d.ts(42,13): error TS2403: Subsequent variable declarations must have the same type.  Variable 'gc' must be of type 'cc', but here has type '(() => void) | undefined'.

TSCC: The compilation has terminated with an error.

I tired using tsc's -outputDir` flag, but this just generated a warning that it was ignored:

$ npx tscc -- -outDir build/src
TSCC: Module option is set. tsickle converts TypeScript modules to Closure modulesvia CommonJS internally, so it will be overridden to "commonjs".
TSCC: --outDir option is set, but it is no-op for tscc.Use prefix option in spec file to control output directory.
...

which is why I added the prefix directive totscc.spec.json. But it appears that prefix is applied only to the output of closure compiler, not the output of tsc.

How can I build a project containing a mix of .ts and .js input files? Given that base.js is mandatory for Closure-based projects, this is presumably supported somehow.

@cpcallen cpcallen changed the title Including .js files in input causes "error TS5055: Cannot write file '_filename.js_' because it would overwrite input file. Including .js files in input causes "error TS5055: Cannot write file '_filename.js_' because it would overwrite input file." Oct 19, 2022
@cpcallen
Copy link
Author

cpcallen commented Oct 19, 2022

Two additional questions, if you would be so kind:

  1. What's with the "Subsequent variable declarations" error in the error output quoted above? Nothing in our project directly uses the @types/node npm module—in fact, there are (or at least should be) no external dependencies at all in the source files supplied to tscc.
  2. Adding (paraphrased for context):
    {
      "compilerOptions": {
        "declaration": true,
        // Generate declaration maps used for api-extractor
        "declarationMap": true,
      }
    }
    
    to tsconfig.json generates two additional error messages:
    tsconfig.json(16,5): error TS5069: Option 'declarationMap' cannot be specified without specifying option 'declaration' or option 'composite'.
    tsconfig.json(18,5): error TS5069: Option 'declarationMap' cannot be specified without specifying option 'declaration' or option 'composite'.
    
    which are nonsensical, as it complains about seeing 'declarationMap' without 'declaration' on the line with the 'declaration' directive. Huh?

@theseanl
Copy link
Owner

theseanl commented Oct 19, 2022

Hi, thank you for the detailed report. The build setup of the blockly repository looks quite complicated, but I see some points that need to be addressed to begin with.

Firstly, I see several closure-style JS files are being fed. Those should only be fed to closure compiler, not to tsickle. To achieve this, in tsconfig.json, compilerOptions.allowJs can be changed to false, or you can specify a file extension .ts in globs in include property. In order to feed closure JS to closure compiler, jsFiles option should be used. So you can provide a glob which selects those files in blocks/**/*.js and tests/compile/**/*.js.

Next, I see several files which reference goog via the following line.

import * as goog from '../closure/goog/goog.js';

It should be replaced with

///<reference path="../node_modules/@tscc/tscc/third_party/closure_library/base.d.ts" />
import * as goog from 'goog:goog';
  • In order for this to work, a npm dependency @tscc/tscc has to be installed somewhere.
  • It seems that the repository has an eslint rule that bans usage of triple slash directives. I have no idea of why such a rule must be present.

Another painful issue is that the entry file must be TS, not a closure-js as it is in the develop branch. Then it has to call goog.require somewhere in a TS file to reference closure JS such as Blockly.libraryBlocks.logic. How it's supposed to work in tscc is this: Every file that a TS file references but whose source is not provided as TS should be considered external via relative paths, so such files must be specified in tscc.spec.json's external key, and accompanied with an ambient module declaration (declare module "Blockly.libraryBlocks.logic" { /* ... */ }), and

goog.require('Blockly.libraryBlocks.logic');

must be changed to

import 'goog:Blockly.libraryBlocks.logic'

The goog:Blockly.libraryBlocks.logic part may need to be changed to something else, I'm not exactly sure how tsickle would treat goog.declareModuleId calls.
Thankfully, it seems that the export object of such closure-JS are not being used, so no additional type declarations are needed.

All these look quite labouring, and it is definitely not the best explanation of what need to be done, but if this makes any sense, I see no fundamental issue that would prevent tscc from working in the blockly repo, so I'd say it's promising.

@theseanl
Copy link
Owner

Regarding your additional questions –

  1. I'm not sure. Tscc uses a slightly different method for discovering dts in node_modules/@types and it may be a reason. But I'd say it is not important, there are more pending tasks, and such an error can be dealt later on.
  2. Since tscc does not create declaration files, it silently sets declaration compiler option to false. I guess it should do the same thing with declarationMap.

theseanl added a commit that referenced this issue Oct 20, 2022
As reported in
#768 (comment),
declarationMap flag may cause the compilation to error out if
declaration is set to false. The rationale is that it would be a bad
experience if tsc succeeds but tscc fails for no apparent reason.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants