Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack: import TypeScript module both "normally" and as raw string

Using webpack ^v2.2.1, I would like to import a TypeScript module as text, in addition to importing the same module "normally".

I've figured that I probably should use the raw-loader. But it isn't working out.

Some example code:

import DemoComponent from './demo'
import demoCode from 'raw-loader!./demo'

TypeScript is screaming at me that something like

error TS2307: Cannot find module 'raw-loader!./demo'.

I'm using ts-loader.

Here is my webpack.config.js:

const { resolve } = require('path')
const fail = require('webpack-fail-plugin')

const config = {
  entry: './docs/index.ts',
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'docs-build')
  },
  resolve: {
    extensions: [ '.ts', '.js' ]
  },
  devtool: 'inline-source-map',
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.js$/,
        loader: 'source-map-loader'
      },
      {
        test: /\.ts$/,
        loader: 'ts-loader'
      },
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              sourceMap: true
            }
          },
          'sass-loader'
        ]
      }
    ]
  },
  plugins: [
    fail
  ]
}

module.exports = config
like image 885
mightyiam Avatar asked Mar 06 '17 17:03

mightyiam


3 Answers

In case anyone is searching for a solution to this answer. Using import is the best option - it will be typed and allow optimizations from module bundlers like Rollup and Webpack 3+ when outputting import vs require:

You need to create a raw-loader.d.ts and make sure it is included by your tsconfig.jsonfile. Enter the following contents:

declare module '!!raw-loader!*' {
  const contents: string
  export = contents
}

tsconfig.json:

{
    "compilerOptions": {
        "types": ["raw-loader.d.ts", "node"]
    }
}
like image 66
Nicholas Boll Avatar answered Nov 14 '22 11:11

Nicholas Boll


It seems that the following is working:

import DemoComponent from './demo'
const demoCode = require('!!raw-loader!./demo')

But I'm not sure how correct this is. I would love to find some documentation about the order and mechanism of loaders.

Also, I would prefer to be consistent, by using import statements, instead. But TypeScript is complaining about it if I do a straight conversion:

import DemoComponent from './demo'
import demoCode from '!!raw-loader!./demo'

The error is a simple

error TS2307: Cannot find module '!!raw-loader!./demo'.
like image 28
mightyiam Avatar answered Nov 14 '22 10:11

mightyiam


I've written a full explanation about it here: https://yonatankra.com/how-to-solve-ts2307-cannot-find-module-when-using-inline-webpack-loaders-with-typescript/

In summary:

You can import using this syntax: import template from 'raw-loader!./component.template.html';

For this to work for any type of file you'd need to:

  1. Setup a module declaration: raw-loader.d.ts
declare module '!!raw-loader!*' {
  const contents: string
  export default contents
}
  1. Use it in your tsConfig.json and add the allowSyntheticDefaultImports property to allow modules without a default export to be imported this way:
{
  "compilerOptions": {
    "types": ["raw-loader.d.ts", "node"],
    "allowSyntheticDefaultImports": true
}

In the article I also explain how to make this work if (for some truly bizarre reason) you'd like to use template.default.

like image 1
yccteam Avatar answered Nov 14 '22 12:11

yccteam