Webpack output structure changes, depending on files outside the entry

486 Views Asked by At

My goal is to create a React component library with TypeScript. I have configured webpack to bundle my components and everything works as expected until I create a folder, that is outside the scope of the entry and which includes TypeScript files.

I have simplified the config as much as possible and I can still reproduce the problem.

webpack.config.js
const path = require('path');

const jsConfig = {
  entry: './src/components/index.ts',
  module: {
    rules: [
      {
        test: /\.ts(x?)?$/,
        exclude: /node_modules/,
        use: {
          loader: 'awesome-typescript-loader'
        }
      }
    ]
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'index.js',
    libraryTarget: 'commonjs2',
    pathinfo: true
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js']
  },
  externals: {
    react: 'react',
    'react-dom': 'react-dom'
  },
  optimization: {
    minimize: false,
    usedExports: true,
    sideEffects: false
  },
  mode: 'production'
}

const configuration = [jsConfig];
module.exports = configuration;
tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "jsx": "react",
    "target": "es5",
    "lib": [
      "es2015",
      "dom"
    ],
    "outDir": "dist",
    "sourceMap": false,
    "declaration": true,
    "moduleResolution": "node"
  }
}

Here is the initial folder structure:

|-- node_modules
|-- src
|   `-- components
|       |-- Button
|       |   `-- Button.tsx // Example component
|       `-- index.ts // A file that exports all components
|-- package.json
|-- tsconfig.json
`-- webpack.config.js

When I run webpack, it creates a dist folder with the following structure:

-- dist
   |-- Alert
   |   `-- Alert.d.ts
   |-- index.d.ts
   `-- index.js

This is what I'm trying to achieve. However, I want to add, let's say, a helper function, and create a folder called helpers in src. Then I add a simple helper.ts file and just add a function that logs something on the console. I'm not exporting anything and I haven't invoked the helper function yet. So if I run webpack now, the dist will look like this:

-- dist
   |-- components
   |   |-- Alert
   |   |   `-- Alert.d.ts
   |   `-- index.d.ts
   `-- index.js

I suppose there is something essential, that I'm missing in understanding webpack's workflow. Why does this components folder emerge in the build output? Notice that it also wraps the index.d.ts - definitely not what I'm going for.

Thanks in advance!

1

There are 1 best solutions below

0
On BEST ANSWER

After a few days on this issue, I think I've found the answer. I will describe my steps to fixing the problem:

  1. This is not a problem with webpack.
    I realised that if the helper file is not with TypeScript extension, the build output does not change.
  2. There is no problem with the TypeScript loader
    I replaced awesome-typescript-loader with ts-loader - the results were the same, the output folder structure changes depending on whether the helper is a TypeScript file or not. Moreover, I didn't find any configuration options for the loader, which would solve the issue.
  3. It's all about the configuration of TypeScript compiler
    I had to pay more attention on the fact that both loaders I tried make use of the tsconfig.json. The docs show that I can set the files or include/exclude properties of the configuration object, which will affect the end result of compilation. Here is the answer to the question why unused files are compiled:

If the "files" and "include" are both left unspecified, the compiler defaults to including all TypeScript (.ts, .d.ts and .tsx) files in the containing directory and subdirectories except those excluded using the "exclude" property.

One more thing to add, since I mentioned the location of index.d.ts in the output folder structure: My goal for helper.ts was to use it in the components, of course. Therefore I had to accept that with the current configuration, my output folder structure changes, because the helper file had be transpiled. This caused the type definition file to end in the components folder. I simply moved the index.ts (which exports the components) one level above - in src and updated the webpack entry file.

I hope this helps someone.