12

I'm integrating typescript in my React app which has significant amount of code. I've some app level HOCs which I apply on React Components as :

import React from 'react';
import HOC1 from 'app/hocs/hoc1';
import compose from 'recompose/compose;

class MyComponent from React.Component {
     ...component stuff...
}

export default compose(HOC1())(MyComponent);

But now I've added typescript in my application, whenever I'm importing

import HOC1 from 'app/hocs/hoc1';

it says

TS2307: Cannot find module 'app/hocs/hoc1'.

I don't want to add type definitions to all my HOCs. What is the solution and why I'm getting this error?

[EDIT] I'm using baseUrl in tsconfig as well. My folder structure is

/Project/configs/tsconfig
/Project/src/app/hocs

In tsconfig, I've given baseUrl as ../src through this documentation.

Another Edit And my webpack config looks like :

    {
        test: /\.(t|j)sx?$/,
        loader: 'happypack/loader?id=jsx-without-proptypes',
        include: [
          path.resolve(__dirname),
          path.resolve(__dirname, '../src'),
        ],
      },

The whole webpack config looks something like

const config = {
  context: path.resolve(__dirname, '../src'),

  mode: NODE_ENV,

  optimization: {
    splitChunks: false,
    nodeEnv: NODE_ENV,
    minimize: false,
  },

  node: {
    net: 'empty',
  },

  output: {
    path: path.resolve(__dirname, '../build/public/assets'),
    publicPath: '/assets/',
    sourcePrefix: '  ',
    pathinfo: DEBUG, //https://webpack.js.org/configuration/output/#output-pathinfo
  },

  module: {
    noParse: [/html2canvas/],
    rules: [
      {
        test: /\.tsx?$/,
        enforce: 'pre',
        use: { loader: 'awesome-typescript-loader' },
      },
      ...shimLoaders,
      ...selectiveModulesLoader,
      {
        test: /\.(t|j)sx?$/,
        loader: 'happypack/loader?id=jsx-without-proptypes',
        include: [
          path.resolve(__dirname),
          path.resolve(__dirname, '../src'),
        ],
      },
      {
        test: /\.jsx?$/,
        loader: 'happypack/loader?id=jsx-without-lodash-plugin',
        include: [
          path.resolve(__dirname, '../src/app/modules/insights/'),
        ],
        exclude: /node_modules/,
      },
      {
        test: /\.jsx?$/,
        loader: 'happypack/loader?id=jsx-with-proptypes',
      },
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        query: {
          presets: [['env', { include: ['babel-plugin-transform-es2015-template-literals'] }]],
        },
      },
      {
        test: /\.css$/,
        use: getCssLoaders({
          pwd: PWD,
          debug: DEBUG,
        }),
      },
      ...getScssRules(DEBUG, PWD),
      {
        test: /\.less$/,
        use: [DEBUG ? 'css-loader' : 'css-loader?minimize', 'less-loader'],
      },
      {
        test: /\.txt$/,
        loader: 'raw-loader',
      },
      {
        test: /\.svg$/,
        loader: 'spr-svg-loader',
      },
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        loader: 'url-loader',
        query: {
          name: DEBUG ? '[path][name].[ext]' : '[hash].[ext]', // ?[hash]
          limit: 10000,
        },
      },
      {
        test: /\.(woff|woff2)$/,
        loader: 'url-loader?name=fonts/[name].[ext]&limit=65000&mimetype=application/font-woff',
      },
      {
        test: /\.(otf|ttf)$/,
        loader: 'url-loader?name=fonts/[name].[ext]&limit=65000&mimetype=application/octet-stream',
      },
      {
        test: /\.eot$/,
        loader: 'url-loader?name=fonts/[name].[ext]&limit=65000&mimetype=application/vnd.ms-fontobject',
      },
      {
        test: /\.(wav|mp3)$/,
        loader: 'file-loader',
        query: {
          name: DEBUG ? '[path][name].[ext]' : '[hash].[ext]', // ?[hash]
        },
      },
      {
        test: /\.pug/,
        loader: 'pug-loader',
      },
      {
        test: /\.html$/,
        include: /src\/app/,
        loader: StringReplacePlugin.replace({
          replacements: [
            {
              //Replaces ES6 strings from languagePack to simple string
              pattern: /__\(\s*`([^`]*)`\s*\)/gi,
              replacement: (match, p1) => {
                let replacedStr = p1;
                replacedStr = replacedStr.replace(new RegExp('\\$\\{([\\w\\.\\:\\-]+)\\}', 'g'), '\' + $1 + \'');
                return `'${replacedStr}'`;
              },
            },
            {
              //Following methods - look out carefully for the *quotes* (single/double)
              //doing what i18nPlugin would do for html files - with the *single* quotes
              pattern: /__\(\s*'(.+?)'\s*\)/g,
              replacement: (match, p1) => {
                const replacedStr = p1;
                return `'${replacedStr}'`;
              },
            },
            {
              //doing what i18nPlugin would do for html files - with the *double* quotes
              pattern: /__\(\s*"(.+?)"\s*\)/g,
              replacement: (match, p1) => {
                const replacedStr = p1;
                return `"${replacedStr}"`;
              },
            },
          ],
        }),
      },
    ],
  },
  resolve: {
    modules: [
      path.resolve(PWD),
      path.resolve(PWD, '..'),
      'node_modules',
      'web_modules',
      'src',
    ],
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.webpack.js', '.web.js'],
    alias: ALIAS,
    // symlinks: false, //https://webpack.js.org/configuration/resolve/#resolve-symlinks, https://github.com/webpack/webpack/issues/1643
  },

  plugins: [getProvidePlugin(), getLoaderOptionPlugin({ debug: DEBUG }), ...getHappypackPlugin({ debug: DEBUG })],

  resolveLoader: {
    modules: ['node_modules', path.resolve(PWD, '../../node_modules'), path.resolve(PWD, './config/loaders/')],
    alias: {
      text: 'raw-loader', // treat text plugin as raw-loader
      jst: 'ejs-loader',
      style: 'style-loader',
      imports: 'imports-loader',
    },
  },

  bail: !DEBUG,

  watch: DEBUG,

  cache: DEBUG,

  stats: DEBUG ?
    {
      colors: true,
      reasons: false,
      hash: VERBOSE,
      version: VERBOSE,
      timings: true,
      chunks: false,
      chunkModules: VERBOSE,
      cached: VERBOSE,
      cachedAssets: VERBOSE,
      performance: true,
    } :
    { all: false, assets: true, warnings: true, errors: true, errorDetails: false },
};

Another Edit

Alias as defined on webpack config also didn't do the trick.

Gatsbimantico
  • 1,822
  • 15
  • 32
Ajay Gaur
  • 5,140
  • 6
  • 38
  • 60
  • In your `tsconfig.json` do you have `"allowJs": true`? – Explosion Pills Oct 26 '18 at 12:57
  • also, if you're importing a local module, you need to specify that by using `./` in the path, e.g. `import HOC1 from './app/hocs/hoc1'` – mehmetseckin Oct 26 '18 at 12:58
  • I've `"allowJs": true` in my tsconfig – Ajay Gaur Oct 26 '18 at 13:06
  • And isn't there any way instead importing everything relatively because importing 100 files relatively clutter up things – Ajay Gaur Oct 26 '18 at 13:06
  • @AjayGaur You can import all the files to a single js file then import the single file into you main app component. – Marc M. Oct 26 '18 at 13:22
  • Do you use Webpack? It enables adding other directories to [`resolve`](https://webpack.js.org/configuration/resolve/) when it looks for modules. – Ross Allen Oct 26 '18 at 13:26
  • I'm using `webpack` and I've `resolve` for modules which is working perfectly for JS but not for TS – Ajay Gaur Oct 26 '18 at 13:30
  • Since your `tsconfig.json` file is in a nonstandard location, are you sure you have configured your TypeScript loader to honor it? I am just guessing at the problem. If you provide sufficient code for me to reproduce the problem (i.e., complete source files, `tsconfig.json`, and webpack configuration, or just a repository), then I can investigate on my own. – Matt McCutchen Oct 28 '18 at 21:01
  • @MattMcCutchen I've updated the question with the configuration. Also, I've removed a few things from the configuration because that would be against the policy of the workplace I work for. Although it should be enough to resolve the issue. Please let me know if you need anything else – Ajay Gaur Oct 29 '18 at 06:27
  • Can you please provide a _complete_ Webpack configuration so I can run Webpack and see the problem for myself without having to take a lot of guesses at how to fill in the parts you haven't provided? The configuration you provide doesn't have to be the same as your original configuration; it just has to demonstrate the same problem. – Matt McCutchen Oct 29 '18 at 12:37
  • Did you try adding the HOC folder as an alias in your webpack config? – Ralph Najm Oct 29 '18 at 13:01
  • @RalphNajm Adding alias in webpack won't be a scalable solution (if) – Ajay Gaur Oct 30 '18 at 10:22
  • @MattMcCutchen I've added the webpack configuration file – Ajay Gaur Oct 30 '18 at 10:22
  • @AjayGaur "Adding alias in webpack won't be a scalable solution". Alias are scalable as you don't need to add all the folders; just a root shared one `src/app` for example, name it as your project `'@my-project': path.resolve(__dirname, 'src/app')` and then use it as `from '@my-project/hocs/hoc1'` – Gatsbimantico Nov 01 '18 at 17:19
  • Also you had a typo `form` instead of `from`, I hope that wasn't what was wrong. – Gatsbimantico Nov 01 '18 at 17:21
  • 1
    That was when I was typing here. No typing error in my code. – Ajay Gaur Nov 02 '18 at 05:20
  • Stumbled upon this little guy: https://github.com/dividab/tsconfig-paths-webpack-plugin He takes `baseUrl` from your `tsconfig.json` and uses it to resolve absolute paths! – seeker_of_bacon Apr 23 '19 at 17:09

2 Answers2

8

https://webpack.js.org/configuration/resolve/#resolve-alias

Using Alias

To map the imports to the right files you'll need to use the config.resolve.alias field in the webpack configuration.

Where in your scenario will look like:

const config = {
  resolve: {
    alias: {
      'app': path.resolve(__dirname, 'src/app/'),
    },
  },
};
Gatsbimantico
  • 1,822
  • 15
  • 32
0

I am not 100% sure I am doing it right, but I also specify paths key in tsconfig, like this:

"baseUrl": "./src",
"paths": {
  "@common/*": ["./common/*"],
  "@moduleA/*": ["./moduleA/*"],
  "@moduleB/*": ["./moduleB/*"],
}

and it seems to work all right. @ prefix is just something i do to discern between my modules and npm dependencies

simka
  • 851
  • 8
  • 9