vuepress / core

Vue-Powered Static Site Generator
https://vuepress.vuejs.org
MIT License
2.17k stars 923 forks source link

[Feature request] Support `?lazy` for vite and webpack or at least `?inline` for webpack #1351

Open Mister-Hope opened 1 year ago

Mister-Hope commented 1 year ago

Clear and concise description of the problem

Currently all styles are extracted to a single file then loaded at page entry. However, some components maybe async, e.g.:

export default defineAsyncComponent({
  loadingComponent: LoadingIcon,
  loader: () => Promise.all([
    import('lib'),
    import('lib/style.css'),
   ]).then([lib]) => defineComponent({
      // actual component
   })),
});

// or something like while calling it with defineAsyncComponent
// component.ts
import 'lib/styles.css';

export default defineComponent({
  setup: () => {
    onMounted(() => {
      import('lib').then([lib]) =>{
        // do something 
     });
   },
});

// client.ts
export default {
  enhance: ({app}) => {
    app.component('component', defineAsyncComponent(()=>import("./component.ts"))):
  },
}

In this case, lib/style.css should better be loaded with the component, i.e., the time entering a page that has that component.

With a lot of async components with styles, the main CSS can be at large size, while a large part of style declarations unused in page.

Suggested solution

Add support for ?lazy to mark a css, and left it without being extracted, this could be difficult as we must develop vite plugin and webpack loader.

export default defineAsyncComponent({
  loadingComponent: LoadingIcon,
  loader: () => Promise.all([
    import('lib'),
    import('lib/style.css?lazy'), // won't be extracted
   ]).then([lib]) => defineComponent({
      // actual component
   })),
});

// or something like while calling it with defineAsyncComponent
// component.ts
import 'lib/styles.css?lazy'; // won't be extracted

export default defineComponent({
  setup: () => {
    onMounted(() => {
      import('lib').then([lib]) =>{
        // do something 
     });
   },
});

// client.ts
export default {
  enhance: ({app}) => {
    app.component('component', defineAsyncComponent(()=>import("./component.ts"))):
  },
}

Alternative

Support ?inline modifier for webpack lite vite does, so we can import style content and load them with functions like useStyleTag from @vueuse, e.g.:

export default defineAsyncComponent({
  loadingComponent: LoadingIcon,
  loader: () => Promise.all([
    import('lib'),
    import('lib/style.css?inline'),
   ]).then([lib,{default: style ]) => defineComponent({
      // actual component
      setup(){
        useStyleTag(style, { id: 'ComponentName' });
        // ...
      },
   })),
});

Additional context

No response