Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(global): support vite inline import #2570

Closed
wants to merge 2 commits into from

Conversation

lisonge
Copy link

@lisonge lisonge commented May 4, 2023

fix #2533

because of vitejs/vite#12912, the HMR of the virtual module is unavailable by default at the moment

Before it is fixed, it is also working by /__uno.css?inline

import unocssText from 'virtual:uno.css?inline';

const unocssStyle = document.createElement('style');
unocssStyle.dataset.source = 'unocss'
unocssStyle.textContent = unocssText;
export default unocssStyle;

if (import.meta.hot) {
    import.meta.hot.accept('/__uno.css?inline', (newModule) => {
        const text2 = newModule?.default as string;
        unocssStyle.textContent = text2 ?? ``;
    });
}

@lisonge lisonge requested a review from antfu as a code owner May 4, 2023 13:35
@netlify
Copy link

netlify bot commented May 4, 2023

Deploy Preview for unocss ready!

Name Link
🔨 Latest commit 1e5269c
🔍 Latest deploy log https://app.netlify.com/sites/unocss/deploys/6453c4d8a092490008bcdaeb
😎 Deploy Preview https://deploy-preview-2570--unocss.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@enpitsuLin
Copy link
Contributor

enpitsuLin commented May 4, 2023

#2419 may relate to this, maybe ?inline query and ?raw should be the same behavior?


BTW, we are streaming chat for review your pr🤣

@@ -100,7 +101,7 @@ export function GlobalModeBuildPlugin(ctx: UnocssPluginContext<VitePluginConfig>
const layer = resolveLayer(getPath(id))
if (layer) {
vfsLayers.add(layer)
return ` ${getLayerPlaceholder(layer)}`
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@antfu hello, Could you explain to me why revert this line ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I add a head space because I found

chunk.code = await replaceAsync(js, LAYER_PLACEHOLDER_RE, async (_, __, layer) => {
replaced = true
const css = getLayer(layer, js)
return css
.replace(/\n/g, '')
.replace(/(?<!\\)(['"])/g, '\\$1')
})

will replace

const xxx = ("#--unocss--{layer:__ALL__} balaba")

to

const xxx = ( *,::before balabal")

more about it can see lisonge/vite-plugin-monkey#45 (comment)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was about to ask why a space it added - I think adding a space is not the correct solution. Instead we should fix it in replacing.

@@ -197,13 +216,16 @@ try {
if (!import.meta.url.includes('?'))
await new Promise(resolve => setTimeout(resolve, 100))`

// Reload full page when using `?inline` - any better solution?
if (isInlineCssMod)
hmr += '\nimport.meta.hot.accept(() => location.reload())\n'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import unocssText from 'virtual:uno.css?inline';

const unocssStyle = document.createElement('style');
unocssStyle.dataset.source = 'unocss'
unocssStyle.textContent = unocssText;
export default unocssStyle;

if (import.meta.hot) {
    import.meta.hot.accept('/__uno.css?inline', (newModule) => {
        const text2 = newModule?.default as string;
        unocssStyle.textContent = text2 ?? ``;
    });
}

hmr not working, it will always reload page,


What is the disadvantage of server.reloadModule ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reloadModule is a very new API and does not available in all Vite versions. + we should avoid making side-effects inside .map whenever possible. If it's necessary, we should

  1. Check if reloadModule exists on server, and fallback to custom logic when using with lower version
  2. Move the calls outside of .map, using .forEach or others.

I actually found either solution works for HMR. Did you manually write the HMR handling?

@antfu antfu marked this pull request as draft May 6, 2023 13:34
@antfu
Copy link
Member

antfu commented May 6, 2023

I think the solution is incomplete, and I need to find another time to do a full revisit. Marked as a draft for now. Feel free to push any changes you think making sense.

@stale
Copy link

stale bot commented Jul 9, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jul 9, 2023
@stale stale bot closed this Jul 16, 2023
@antfu antfu reopened this Jul 16, 2023
@stale stale bot removed the stale label Jul 16, 2023
@lisonge
Copy link
Author

lisonge commented Aug 5, 2023

A simple way to customize unocss global style side effect

it work well with hmr and shadow-dom

test-example

Although there may be defects, it meets my needs

import { build } from '@unocss/cli';
import fs from 'node:fs/promises';
import unocss from 'unocss/vite';
import type { ConfigEnv, Plugin } from 'vite';

const iframeTemplate = /* html */ `
<script type="module">
// base must be '/'
import '/@vite/client';
import '/__uno.css';

const unoStyle = document.querySelector(
  'head style[data-vite-dev-id="/__uno.css"]',
);
const update = ()=>{
  parent.postMessage(
    {
      type: '__unocss_update',
      textContent: unoStyle?.textContent,
    },
    '*',
  );
}
if (window != parent) {
  update();
  new MutationObserver(update).observe(unoStyle, {
    childList: true,
    attributes: true,
  });
}
</script>
`.trim();

const moduleTemplate = /* js */ `
const style = document.createElement('style');
style.textContent = __UNOCSS_TEXT__;
export default style;
if (import.meta.env.DEV) {
  const origin = new URL(import.meta.url).origin;
  window.addEventListener('message', (event) => {
    const data = event.data || {};
    if (data.type == '__unocss_update') {
      style.textContent = data.textContent;
    }
  });
  const iframe = document.createElement('iframe');
  iframe.src = origin + '/__unocss_iframe';
  iframe.style.display = 'none';
  document.head.append(iframe);
}
`.trim();

export const unocssStyle = async (env: ConfigEnv): Promise<Plugin[]> => {
  const dev = env.command == 'serve';
  const unocss_text = await (async () => {
    if (!dev) {
      // or use createGenerator({},{}).generate(code)
      await build({
        cwd: process.cwd(),
        config: './unocss.config.ts',
        patterns: ['./src/**/*.{js,mjs,ts,jsx,tsx,vue,svelte}'],
        stdout: false,
        minify: true,
        outFile: './uno-prebuilt.css',
      });
      const text = (await fs.readFile('./uno-prebuilt.css', 'utf-8')).trim();
      await fs.unlink('./uno-prebuilt.css');
      return text;
    } else {
      return '';
    }
  })();

  return [
    {
      name: 'unocss:style',
      resolveId(source) {
        if (source == `unocss?style`) return `__unocss_style`;
      },
      async load(id) {
        if (id == `__unocss_style`) {
          return moduleTemplate.replace(
            '__UNOCSS_TEXT__',
            JSON.stringify(unocss_text),
          );
        }
      },
      configureServer(server) {
        server.middlewares.use(async (req, res, next) => {
          if (req.url?.startsWith(`/__unocss_iframe`)) {
            res.setHeader('content-type', 'text/html');
            res.end(iframeTemplate);
            return;
          }
          next();
        });
      },
    },
    ...(dev ? unocss() : []),
  ];
};
// main.tsx
import { render, Portal } from 'solid-js/web';
import style from 'unocss?style';
import App from './App';

render(
  () => (
    <Portal useShadow>
      <App />
      {style}
    </Portal>
  ),
  (() => {
    const div = document.createElement('div');
    document.body.append(div);
    return div;
  })(),
);

@stale
Copy link

stale bot commented Oct 4, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Oct 4, 2023
@zyyv zyyv removed the stale label Oct 9, 2023
Copy link

stale bot commented Dec 8, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

the default export and sideEffects of virtual:uno.css?inline
4 participants