JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 92268
  • Score
    100M100P100Q177002F
  • License MIT

Inject css at the top of chunk file in lib mode using `import` statement, support multiple entries.

Package Exports

  • vite-plugin-lib-inject-css

Readme

vite-plugin-lib-inject-css

English | 简体中文

Inject css at the top of each chunk file in lib mode using import statement like this:

// bundled js file, with import css at top (if any)
import './style.css';
// rest of the file
// ...

Can css be styleInjected in library mode? vite#1579.

Features

Note that this plugin only works with library-mode.

  • 💡 Multiple entires support.
  • ⚡️ Sourcemap support.
  • 🛠 Out-of-box, tiny and pretty.

Usage

Install:

pnpm i vite-plugin-lib-inject-css -D # npm/yarn

Config:

// vite.config.ts
import { libInjectCss, scanEntries } from 'vite-plugin-lib-inject-css';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    libInjectCss(), // For a simple usage
    // Parameters are optional, which is only an alias, aim to make configs concise.
    libInjectCss({
      format: ['es'],
      entry: {
        index: 'src/index.ts', // Don't forget the main entry!
        button: 'src/components/button/index.ts',
        select: 'src/components/select/index.ts',
        // Uses with a similar directory structure.
        ...scanEntries([
          'src/components',
          'src/hooks',
        ])
      },
      rollupOptions: {
        output: {
          // Put chunk files at <output>/chunks
          chunkFileNames: 'chunks/[name].[hash].js',
          // Put chunk styles at <output>/styles
          assetFileNames: 'assets/[name][extname]',
        },
      },
    }),
  ],
})

Motivation

Vite shines for Web projects, but it can also be used for library projects.

But when it comes to component library development, multiple entries are often involved. Although Vite 3.2+ supports multiple entry points, it doesn't provide any configuration for us to associate css with component, which leads to the problem that we can't distinguish between the entry point and css files even though the bundle is successful.

Based on this, we need to write a plugin to inject styles so that we don't have to worry about the relationship between styles and entry points.

How does it work

As a library(mostly component library), we want to import styles automatically when we reference the component.

/** component-lib/dist/button.js */
import './assets/button.css'; // This is what this plugin do;
...
export default Button;

/** component-lib/dist/index.js */ 
import Button from './button.js';
import xxx from './xxx.js';
export { Button, xxx };
...

/** In our project's main file */
// Once we import Button, styles'll be imported together.
import { Button } from 'component-lib';

As shown above, it's not graceful to manually write code like document.createElement('script') to inject the style into the page, that assumes dom environment.

What we do is just inject code like import './style.css' at the top of each chunk, which delegate the task of how to handle these css files to the user's build tool.

So the main problem becomes to how do we know which style files are involved in one chunk file?.

Fortunately vite adds a property named viteMetadata on each chunk file in plugin lifecycle, so that we can manage to do it using plugin hook like renderChunk, which is simplest and enough.

Prefer to check source code to get more information.

Recipes

How do we create a component library with vite, which can auto import styles and has out-of-box tree-shaking functionality?

Current Status

Most of component libraries provide two ways. One is totally import:

import Vue from 'vue';
import XxxUI from 'component-lib';
Vue.use(XxxUI);

The other is import on demand, in common uses with a third-part plugin like babel-plugin-import:

import { Button } from 'component-lib';
// ↓ ↓ ↓ transformed ↓ ↓ ↓
import Button from 'component-lib/dist/button/index.js'
import 'component-lib/dist/button/style.css'

But the best way is that when we use named imports, the style imports and tree-shaking can be completed automatically, which has little mental burden.

How should we do

  1. Add multiple entries to the build.lib.entry option.

  2. Set build.lib.formats: ['es'] to ensure lib output a ES Module. Because ESM has the ability of static analysis naturally, and mainstream build tools have basically supported ESM-based tree-shaking, such as webpack/rollup/vite.

  3. Add this plugin to your build configurations. It will automatically inject style imports to each chunk file.

Last but not least, add '**/*.css' to the 'sideEffects' field in package.json. This avoid unexpected tree-shaking by user's build tool.

{
  "name": "vite-plugin-lib-inject-css",
  "version": "1.0.0",
  "sideEffects": [
    "**/*.css"
  ]
}

License

MIT License © 2023 秦旭洋