webpack-contrib/raw-loader

Cannot import file using typescript

danman113 opened this issue ยท 6 comments

  • Operating System: OSX
  • Node Version: v8.11.3
  • NPM Version: 5.6.0
  • webpack Version: ^4.19.1
  • raw-loader Version: ^0.5.1

This issue is for a:

  • bug
  • feature request
  • modification request

Code

import txt from './simple.txt'
CLI Command
  webpack
webpack.config.js

webpack.config.js

tsconfig
{
  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es5"
  },
  "include": [
    "./src/**/*"
  ]
}

Expected Behavior

Should load the file and return a string to txt

Actual Behavior

Get the following error after running webpack

ERROR in [at-loader] ./src/index.ts:3:17
    TS2307: Cannot find module './simple.txt'.

How Do We Reproduce?

Simply use the webpack config and import. package.json can be provided as well.

Not really sure if this is an error with the loader, webpack, my config, or awesome-typescript-loader

Also before you asked, I also tried import txt from 'raw-loader!./simple.txt' and import txt from './simple.txt', no dice.

Thanks!

@danman113 it is not bug webpack, looks you should ignore some files in tsconfig

@evilebottnawi That doesn't seem to work. I updated my .tsconfig to the following without any luck:

  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es5"
  },
  "include": [
    "./src/**/*.ts"
  ],
  "exclude": [
    "./src/**/*.txt"
  ]
}

Still get

ERROR in [at-loader] ./src/index.ts:3:22
    TS2307: Cannot find module './simple.txt'.

Okay so I figured out what the problem was, it's definitely not a problem with webpack or the loader, but how typescript handles modules.

The fix was simply to add a [filename].d.ts file in the same directory as with a declaration declare module '*.[filename]' in it. Adding these declaration files is what should fix all of these bugs.

EDIT:
The above fix doesn't seem to be the most robust, bug-free way of fixing this problem. If you need to add another filetype, say in this case a .html file, you might run into bugs with the typescript compiler if you say, try to access that filetype in a different directory. Also it's just annoying to have to make a new file for every filetype.

A better strategy that I've been using is to add a global typescript declaration file, global.d.ts (located right next to my entry file), and just add all of the types in there. Using our example:

declare module '*.txt'
declare module '*.html'

By the way, if use import ... from syntax in your ts file may get silent failure, using import * as ... from will work well

For whoever runs into the same question (like me) in the future. The answer is in the official typescript doc. You'll need to tell typescript that your module will be a string type (or other type).

In raw loader case, the files would look like this:

textfile.txt

some text

textfile.txt.d.ts, the type definition of textfile, next to textfile.txt

declare module "raw-loader!*" {
    const content: string;
    export default content;
}

code.ts

import consttext from "raw-loader!./textfile.txt"

Now typescript would be happy about the string type variable "consttext".

This has been a helpful thread for me! I had a similar problem, but with PDF instead of text files, and file-loader instead of raw-loader.

I followed @danman113's awesome post, and it almost worked - turns out the PDF was being double-processed - once by the webpack config, and once by the !file-loader directive. It worked once I added a 'pdf' exclusion to this part of webpack.config.js:

              loader: require.resolve('file-loader'),
              // Exclude `js` files to keep "css" loader working as it injects
              // its runtime that would otherwise be processed through "file" loader.
              // Also exclude `html` and `json` extensions so they get processed
              // by webpacks internal loaders.
              exclude: [
                /\.(js|mjs|jsx|ts|tsx)$/,
                /\.html$/,
                /\.json$/,
                /\.pdf$/,
              ],
              options: {
                name: 'static/media/[name].[hash:8].[ext]',
              },
            },