Import raw files from typescript with webpack using the `import` statement
Asked Answered
P

3

17

I need to import raw data from typescript using webpack. Here is my setup:

$ tree
.
+-- file.txt
+-- main.ts
+-- package.json
+-- tsconfig.json
+-- webpack.config.js

file.txt

file-content

main.js

import file from './file.txt';

console.log(file);

package.json

{
  "devDependencies": {
    "raw-loader": "^0.5.1",
    "ts-loader": "^3.1.1",
    "typescript": "^2.6.1",
    "webpack": "^3.8.1"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es5",
    "baseUrl": "app"
  },
  "exclude": [
    "node_modules"
  ]
}

webpack.config.js

const path = require('path');

const config = {
  entry: './main.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'app.js'
  },
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' },
      { test: /\.tsx?$/, loader: 'ts-loader' },
    ]
  }
};

module.exports = config;

when I run weback, it says it can't find the module:

ERROR in ./main.ts
[tsl] ERROR in /tmp/test/main.ts(1,18)
      TS2307: Cannot find module './file.txt'.

My question is: How can I import txt data into a typescript file? This is useful when writing an angular component, for example, and importing an html template to assign it to the template property of that component.

Pneumococcus answered 5/11, 2017 at 14:9 Comment(6)
@Fenton: Does not work. And where would the content of the file be? I need it in a variable to use it.Pneumococcus
@Kacper, the question you are referring to is not using webpack but systemjs. Besides, the solution looks like an ugly workaround.Pneumococcus
There is a problem in Typescript modules resolution, so it doesn't matter if you are using systemjs or webpack. Typescript module resolver is looking for .ts/.tsx/.js/.jsx files, so you need to declare module before importing it.Cowell
I believe there is more to it. By creating an appropriate declaration.d.ts there error goes away but it does not work. It prints "undefined". Looking at the generated bundle, the module is messed up somehow. So either webpack or the raw-loader is not getting along with it. I am suprised that this does not work. It used to with js/babel and I would expect people to need that feature.Pneumococcus
You are missing resolve section in you webpack configuration.Cowell
webpack.js.org/guides/typescript/#importing-other-assets in webpack documentation. So you probably need to do the same but for *.txt extension.Cowell
C
23

So I finally got it to work. I have added module declaration in .d.ts file:

declare module '*.txt' {
  const content: any;
  export default content;
}

And only then I imported .txt file like this:

const someTextContent = require('./some.txt');

You can find more about this here.

EDIT:

If you want to use import keyword just use it as following:

import * as someTextContent from './some.txt';
Cowell answered 5/11, 2017 at 19:45 Comment(5)
Yes, I've seen that solution in the discussion of the question you pointed too, but I'd rather keep using import. Using require looks like a workaround to me.Pneumococcus
Edited answer. You can use import easily, but you still have to include module declaration for Typescript in *.d.ts files.Cowell
In your declare module ... statement, you can also use const content: string, so the someTextContent will be a string.Colonel
content type should be string const content: stringHeritor
The import syntax didn't work for me. Changing to require avoids errors on compile, but doesn't copy the included file to the built directory (or pack it). What am I missing? Are there restrictions on what the .d.ts file can be named or where it must live?Hillhouse
I
9

I added a global definition file global.d.ts in src root and added:

declare module "*.txt" {
  const content: any;
  export default content;
}

I didn't need any extra tsconfig.json, and I just had the standard webpack rule for raw-loader:

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

Then I could import a plain text file called ./source.js.txt into ts variable like this:

import txt from './source.js.txt'

It seemed more to do with making TS happy than webpack. The key seems to be the module definition. Either global or per file if needed.

Insurgence answered 23/7, 2019 at 4:29 Comment(1)
It's "Asset Modules" since Webpack v5: webpack.js.org/guides/asset-modulesMiele
J
3

Prior to webpack v5 it was common to use raw-loader to import file contents as a string.

now you can use type: 'asset/source' to import the raw text of a file.

module.exports = {
  module: {
    rules: [
      // ...
      {
        resourceQuery: /raw/,
        type: 'asset/source',
      },
    ],
  },
}

if you use typescript, create a declaration file in your project folder (choose any name):

//declarations.d.ts

declare module '*?raw' {
  const content: string
  export default content
}
- import text from 'file.txt';
+ import text from 'file.txt?raw';

this way, no matter what the file extension is, you can import it as raw text just by adding ?raw to the import address

source: https://webpack.js.org/guides/asset-modules/

Jenna answered 22/10, 2023 at 9:12 Comment(2)
But what about TS files that are already being transpiled by another loader/rule? How do I ?raw load its content before transpilation?Carpi
@Martin if you'd like to exclude raw assets from being processed by other loaders, use a negative condition: webpack.js.org/guides/asset-modules/…Jenna

© 2022 - 2024 — McMap. All rights reserved.