ZiiMakc
ZiiMakc

Reputation: 36876

Webpack & typescript: watch not working for exported intefaces

UPD.

I have two folders frontend and shared that get bundled by webpack using ts-loader.

Problem is that change of exported interfaces from shared folder don't get detected.

If i add in IThemes.ts export like

export const x = 2

than changes are detected again even for interface change.

example of exported IThemes.ts:

export interface IGeneralTheme {
  isDay: boolean
  day: ITheme
  night: ITheme
}

example of interface use ThemeContext.tsx:

import React, { useState, useEffect } from 'react'
import { deepClone, ITheme, IGeneralTheme } from '@shared'
import { ThemeProvider, createGlobalStyle } from 'styled-components'

type ThemeContextProps = {
  theme: ITheme
  generalTheme: IGeneralTheme
  isDay: boolean
  setGeneralTheme: React.Dispatch<React.SetStateAction<IGeneralTheme>>
}

export const ThemeContext = React.createContext<Partial<ThemeContextProps>>({})

tsconfig.base.json:

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "sourceMap": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "removeComments": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "strictBindCallApply": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "allowJs": true,
    "strictPropertyInitialization": true
  },
  "exclude": [
    "../../node_modules"
  ]
}

tsconfig.json in frontend folder:

{
  "extends": "../configs/tsconfig.base.json",
  "include": [
    "**/*",
    "../shared/**/*"
  ],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@shared": [
        "../shared/index"
      ],
      "@frontend": [
        "index"
      ]
    },
    "jsx": "react",
    "target": "es2015"
  }
}

webpack.base.js:

const path = require('path')
const webpack = require('webpack')

module.exports = {
  entry: '../frontend/client.tsx',
  output: {
    path: path.resolve('../../public'),
    filename: 'react_bundle.js'
  },
  devtool: 'source-map',
  resolve: {
    extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
    alias: {
      '@frontend': path.resolve(__dirname, '../frontend/index'),
      '@shared': path.resolve(__dirname, '../shared/index')
    }
  },
  module: {
    rules: [
      {
        test: /\.ts(x?)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader'
          }
        ]
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        enforce: 'pre',
        test: /\.js$/,
        loader: 'source-map-loader'
      }
    ]
  },
  plugins: [new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /ru/)]
}

webpack.dev.js:

const merge = require('webpack-merge')
const base = require('./webpack.base.js')
const webpack = require('webpack')

module.exports = merge(base, {
  mode: 'development',
  watch: true,
  plugins: [
    new webpack.DefinePlugin({
      isProd: false
    })
  ]
})

Runned by command from configs folder: npx webpack --config webpack.dev.js

Upvotes: 4

Views: 3152

Answers (2)

adi518
adi518

Reputation: 862

You have to enable TS compiler option importsNotUsedAsValues, see: https://github.com/TypeStrong/ts-loader/issues/1138

Upvotes: 1

ZiiMakc
ZiiMakc

Reputation: 36876

Found answer to my own question after i saw that it's not working only for interface:

I encountered a similar issue. What solved it for me was to change the filenames of files that contain only interfaces from *.ts to *.d.ts.

Apparently, the ts-loader generates output only for files that give JavaScript output, and typescript definition files. The output is then read by the webpack watcher, and webpack updates if one of these files changes.

In your case, you have files that generate no JavaScript output and are not typescript definition files. So no output will be generated from them, and the webpack watcher won't notice when they change.

Alternative is awesome-typescript-loader that seems work fine.

Upvotes: 6

Related Questions