0

I'm writing a Typescript testcase, which needs some static xml, loaded from an file which is part of the project. I'm using webpack, in a node/typescript project and am finding that VSC typescript is out of step with the project's typescript.

The line which is causing a problem (from VSC perspective) is this (the testcase and the xml file are in the same directory):

import data from './app.config.xml';

In order to get imports to work (in the project) I had to do the following things (Importing Other Assets):

1) ensure that I was using raw-loader in webpack for xml files:

  module: {
    rules: [
      {
        test: /\.xml$/i,
        use: 'raw-loader'
      },

2) declaring a module in a declaration file (./lib/declarations.d.ts)

declare module '*.xml' {
  const content: string;
  export default content;
}

3) include this declation file in the types property of tsconfig

"types": [
  "mocha", "node", "./lib/declarations"
],

In my test case, I am trying to import this as follows:

import data from './app.config.xml';

However, Typescript in VSC is reporting this error:

Cannot find module './app.config.xml'.ts(2307)

This however is not an issue when I build the project. If I remove the module declaration from the declaration file, then the build does indeed fail with this identical error. So somehow, Typescript in VSC is not in sync with the Typescript installed in the project. The version of typescript in VSC and the project are identical (version 3.7.2).

Since the build works, I don't know wether its 'check-in-able'. I don't like seeing errors in VSC particulalry as it is out of step with the project. So far in my Typescript journey, typescript in the project and typescript in VSC have always been in step, so I can't understand whats happening here. I've tried to clean my repo and rebuild but this made no difference.

In VSC I'm using the "Typescript extension Pack (0.2.0)" (which includes TSLine, TypeScript Hero, json2ts, Move TS, Path Intellisense, Tyescript Impoerter, Prettier, Debugger for Chrome) However, I don't believe that any of these plugins are responsible for the error that VSC is reporting. I think that the error is coming from the Typescript support built directly into VSC.

For the sake of completeness, my tsconfig is:

{
  "compilerOptions": {
    "allowJs": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "module": "commonjs",
    "moduleResolution": "Node",
    "noImplicitAny": true,
    "sourceMap": true,
    "strictNullChecks": true,
    "target": "es5",
    "types": [
      "mocha", "node", "./lib/declarations"
    ],
    "lib": [
      "es5",
      "es2015",
      "es6",
      "dom"
    ]
  },
  "include": [
    "lib/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

and webpack file:

const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  devtool: 'source-map',
  mode: 'development',
  entry: ['./tests/all-tests-entry.js', './lib'],
  target: 'node',
  externals: [nodeExternals()],
  module: {
    rules: [
      {
        test: /\.xml$/i,
        use: 'raw-loader'
      },
      { test: /\.ts(x?)$/, loader: 'ts-loader' },
      { test: /\.json$/, loader: 'json-loader' }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js', '.json']
  },
  watchOptions: {
    ignored: /node_modules/
  },
  output: {
    filename: 'test-bundle.js',
    sourceMapFilename: 'test-bundle.js.map',
    path: path.resolve(__dirname, 'dist'),
    libraryTarget: 'commonjs'
  }
};

and ./tests/all-tests-entry.js:

var context = require.context('./', true, /.spec.ts$/);
context.keys().forEach(context);
module.exports = context;

and directory structure with relevant files:

/project-root/
tsconfig.json
webpack.config.test.ts

/project-root/lib/
declaration.d.ts

/project-root/tests/
widget.class.spec.ts
app.config.xml

An here is a snapshot of VSC (with all extensions disabled) reporting an error that doesnt exist in the project build:

enter image description here

Plastikfan
  • 3,674
  • 7
  • 39
  • 54

2 Answers2

2

The mismatch exists because you are using webpack from the command line to compile your code but VS Code uses normal TypeScript to power its IntelliSense.

TypeScript itself does not know how to import arbitrary data files (such as xml). You would see the same error you see in VS Code if you tried to compile your code using tsc instead of webpack.

See these answers for more info and how to workaround the problem in normal TS. Basically, you need to add a d.ts file to your project with a declaration like:

declare module "*.xml" {
const value: string;
  export default value;
}
Matt Bierner
  • 58,117
  • 21
  • 175
  • 206
  • Hi Matt, thanks for your comment. That code sample you provided is exactly what I did already (as part of my research) as I state early on in my post. I have done extensive research into this but I didnt see that issue you found so I'll take a look at that. – Plastikfan Nov 20 '19 at 17:51
  • Try including the declaration in you normal project (not under `types`). To test, paste it at the top of the file that has the xml import – Matt Bierner Nov 20 '19 at 17:54
  • Sorry Matt, I'm not clear what you mean by 'Try including the declaration in you normal project'. I removed "declarations" from "types" in tsconfig.json as you say, but I don't know what you mean when you say 'normal project' – Plastikfan Nov 20 '19 at 18:04
  • Essentially, all I'm looking for is to fix VSC. The project builds ok with webpack, so there's something wrong with VSC. – Plastikfan Nov 20 '19 at 18:05
  • Did you try compiling your project with `tsc`? To add the declaration to your project, just create a `d.ts` file, paste in that declaration, and in run `TypeScript: Go To Project configuration`. This should open the same tsconfig that your normal ts files are part of. If it does not, then make sure your tsconfig includes that `d.ts` file (through `include` / `exclude`, not `types`) – Matt Bierner Nov 20 '19 at 18:32
  • I have tried compiling with tsc, but the error does not appear. It looks like here is a problem with VSC – Plastikfan Nov 21 '19 at 14:40
  • Does `TypeScript: Go To Project configuration` in the d.ts open the correct config file? What if you run the command in the ts file with the import? Does it open the same config? – Matt Bierner Nov 21 '19 at 18:53
0

The fix to this problem is a triple slash directive at the top of the file. Since the import statement depends on the module declaration defined in ./declarations.d.ts, this needs to be preceded by a triple slash reference directive (in my project's case):

/// <reference types="../../lib/declarations" />

Also, I found that another solution that resolved this was to put the declaration file, in the same folder an the importing file. This did not require a triple slash directive.

The only issue is, why is this different for VSC Typescript vs project Typescript built by webpack?

Plastikfan
  • 3,674
  • 7
  • 39
  • 54