1

Question

I am building a UI components library to reuse in my projects. The library is written in TypeScript and .less with React, and built with WebPack.

.
├── README.md
├── dist
├── index.js
├── package-lock.json
├── package.json
├── src
│   ├── Span
│   │   ├── Span.less
│   │   └── index.tsx
│   └── Tag
│       ├── Tag.less
│       └── index.tsx
├── tsconfig.json
├── types
│   └── custom.d.ts
└── webpack.config.js

Each component is exported as a named module. In WebPack I grab each .ts file as an entry, pass it through ts-loader and output it to the dist folder within another folder with the name of the module. Then I process the TypeScript declaration files and send them to this folder structure. With an index.js file in root folder I import each module from their folder, and export it as a named module using commonjs syntax.

// ./index.js
exports.Span = require('./dist/Span').Span;
exports.Tag = require('./dist/Tag').Tag;

In package.json I declare the files of my npm module as [ "/dist", "index.js" ]; Thus, the published npm module will be:

.
├── dist
│   ├── Span
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   └── index.js.map
│   └── Tag
│       ├── index.d.ts
│       ├── index.js
│       └── index.js.map
└── index.js

Finally, from my client code I can import those components as named modules, like:

// client code
import { Span, Tag } from 'components_library_example';

My questions are:

  1. Currently the css files are not loaded.

    • Is there any reason why my client code can't read the inlined css code?
    • Another solution would be to use MiniCssExtractPlugin to extract the css, and import the styles from index.js; easy in theory, but actually, it seems not possible. Is there any good approach there?
  2. Currently, when I import the components, typescript is not recognizing the declaration files, so I loose all types.

    • ¿How can I export the modules in index.js in order to maintain the access to the .d.ts declaration files?

Thanks!


Note: my webpack conf:

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  name: 'server',
  entry: {
    Span: path.join(__dirname, 'src/Span/index.tsx'),
    Tag: path.join(__dirname, 'src/Tag/index.tsx'),
  },
  output: {
    filename: '[name]/index.js',
    path: path.join(__dirname, 'dist'),
    libraryTarget: 'commonjs2',
    globalObject: "(typeof self !== 'undefined' ? self : this)", 
    library: 'MyLib',
    umdNamedDefine: true,
  },
  target: 'node',
  devtool: '#source-map',
  externals: [nodeExternals(), 'react'],
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.svg'],
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx)$/,
        loader: ['ts-loader'],
        exclude: /node_modules/,
      },
      {
        test: /\.(less|css)$/,
        use: ['css-loader', 'less-loader'],
      },
      {
        test: /\.svg$/,
        use: ['@svgr/webpack'],
      },
    ],
  },
  stats: 'errors-only',
  plugins: [
    new CleanWebpackPlugin({
      dry: false,
      verbose: true,
      protectWebpackAssets: false,
      cleanOnceBeforeBuildPatterns: [path.join(__dirname, 'dist', '/**/*')],
    }),
  ],
};

1 Answer 1

1

First of all, webpack is not the most suitable tool for making libraries Currently, each of your components includes a lot of duplicated runtime stuff. Transpiling components to es modules may be enough since you likely will bundle them as parts of some application.

Currently the css files are not loaded. Is there any reason why my client code can't read the inlined css code?

Your styles are included in the bundled files but won't be applied. Styles should be injected into the page somehow and, usually, style-loaded is used for this. Injecting is a side effect so your library won't be tree-shakeable.

Depending on how you are going to use the library I would suggest avoiding importing styles in components and one of the following:

  1. Provide them as less files to consumers if consuming app uses webpack and will process own less files
  2. Process less files and expose one css file that you can include to index.html in any way. It may suit in case of a consumer that does not have a build process, let's say simple static html. And yes it seems unlikely since your components need react :)
  3. Use some css-in-js solution. That is the way most of the react libraries use in 2020.

Currently, when I import the components, typescript is not recognizing the declaration files, so I loose all types. You can add index.d.ts file in the root of your library and reexport all the component types there

export * from './src/Span';
export * from './src/Tag';

If you want to place them somewhere else you need to specify types field in your package.json

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @shlang. Then I will import all my components from a src/index.ts, declare it as the entry for webpack, and this will output a /dist/index.js, /dist/index.d.ts, /dist/index.css and /dist/[module_name]/index.d.ts. I will use webpack for now, but will refactor this build to webpack at some point. Thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.