nonzzz / vite-plugin-stylex

an unofficial @stylexjs vite support
MIT License
50 stars 4 forks source link

Unnecessary duplicate assets included in the build when using `?url` style imports #18

Closed predaytor closed 6 months ago

predaytor commented 6 months ago

Stackblitz

Using side-effect import everything works properly, resulting in single css file:

import './styles/index.css'

Logs:

❯ pnpm build

> remix-demo@ build /home/predaytor/remix-stylex
> remix vite:build

vite v5.2.8 building for production...
✓ 84 modules transformed.
build/client/.vite/manifest.json                1.38 kB │ gzip:  0.41 kB
build/client/assets/root-CfhkM_gF.css           0.60 kB │ gzip:  0.32 kB
build/client/assets/root-D1dZ27zj.js            1.39 kB │ gzip:  0.81 kB
build/client/assets/_index-D5VKFgXt.js          2.03 kB │ gzip:  1.14 kB
build/client/assets/jsx-runtime-BlSqMCxk.js     8.09 kB │ gzip:  3.05 kB
build/client/assets/entry.client-DRdY3GlJ.js   14.06 kB │ gzip:  5.01 kB
build/client/assets/components-Wh-oPew1.js    212.85 kB │ gzip: 68.83 kB
✓ built in 1.55s
vite v5.2.8 building SSR bundle for production...
"create" is imported from external module "@stylexjs/stylex" but never used in "app/theme.stylex.ts", "app/Card.tsx" and "app/routes/_index.tsx".
✓ 8 modules transformed.
build/server/.vite/manifest.json               0.22 kB
build/server/assets/server-build-CfhkM_gF.css  0.60 kB
build/server/index.js                          6.99 kB
✓ built in 90ms

/build/client/assets/root-CfhkM_gF.css:

@layer core {
    * {
        box-sizing: border-box;
    }
}
:root {
    --x: pink;
    --x1yjbm8s: #000;
}
.x1tamke2:not(#\#) {
    padding: 16px;
}
.xur7f20:not(#\#):not(#\#) {
    border-radius: 8px;
}
.x12peec7:not(#\#):not(#\#):not(#\#) {
    background-color: #fff;
}
.x1ik0xcp:not(#\#):not(#\#):not(#\#) {
    box-shadow: 0 0 16px #0000001a;
}
.x3ja3p5:not(#\#):not(#\#):not(#\#) {
    color: #329b25;
}
.x1wzkho:not(#\#):not(#\#):not(#\#) {
    color: #ff6850;
    color: color(display-p3 1.04321 0.334712 0.217808);
    color: lch(64.2906% 106.837 40.8577);
}
.x195j60l:not(#\#):not(#\#):not(#\#) {
    color: var(--x1yjbm8s);
}
@media (max-width: 1024px) {
    .x1yewo9u.x1yewo9u:not(#\#):not(#\#):not(#\#) {
        color: purple;
    }
}

Using manual ?url import results with separate index-ClnSbR9a.css file with the preload link included, which comes from root.tsx, the content of which already is present in root-CfhkM_gF.css. I believe the expected behavior should be similar to side-effect import, including and preloading a single css file (in this case it should be root-CfhkM_gF.css):

import $styles from '~/styles/index.css?url';

export const links: LinksFunction = () => [
    // Preload CSS as a resource to avoid render blocking
    { rel: 'preload', href: $styles, as: 'style' },

    // These should match the css preloads above to avoid css as render blocking resource
    { rel: 'stylesheet', href: $styles },
];

Devtools:

<!-- ... -->
<link rel="stylesheet" href="/assets/root-CfhkM_gF.css" />
<link rel="preload" href="/assets/index-ClnSbR9a.css" as="style" />
<link rel="stylesheet" href="/assets/index-ClnSbR9a.css" />

Logs:

❯ pnpm build

> remix-demo@ build /home/predaytor/remix-stylex
> remix vite:build

vite v5.2.8 building for production...
✓ 85 modules transformed.
build/client/.vite/manifest.json                1.55 kB │ gzip:  0.45 kB
build/client/assets/index-ClnSbR9a.css          0.07 kB │ gzip:  0.08 kB
build/client/assets/root-CfhkM_gF.css           0.60 kB │ gzip:  0.32 kB
build/client/assets/root-CBQOkiJk.js            1.51 kB │ gzip:  0.89 kB
build/client/assets/_index-D5VKFgXt.js          2.03 kB │ gzip:  1.14 kB
build/client/assets/jsx-runtime-BlSqMCxk.js     8.09 kB │ gzip:  3.05 kB
build/client/assets/entry.client-DRdY3GlJ.js   14.06 kB │ gzip:  5.01 kB
build/client/assets/components-Wh-oPew1.js    212.85 kB │ gzip: 68.83 kB
✓ built in 1.77s
vite v5.2.8 building SSR bundle for production...
"create" is imported from external module "@stylexjs/stylex" but never used in "app/theme.stylex.ts", "app/Card.tsx" and "app/routes/_index.tsx".
✓ 9 modules transformed.
build/server/.vite/manifest.json               0.38 kB
build/server/assets/index-ClnSbR9a.css         0.07 kB
build/server/assets/server-build-CfhkM_gF.css  0.60 kB
build/server/index.js                          7.30 kB
✓ built in 137ms

/build/client/assets/index-ClnSbR9a.css:

@layer core {
    * {
        box-sizing: border-box;
    }
}
:root {
    --x: pink;
}
@stylex-dev;

/build/client/assets/root-CfhkM_gF.css:

@layer core {
    * {
        box-sizing: border-box;
    }
}
:root {
    --x: pink;
    --x1yjbm8s: #000;
}
.x1tamke2:not(#\#) {
    padding: 16px;
}
.xur7f20:not(#\#):not(#\#) {
    border-radius: 8px;
}
.x12peec7:not(#\#):not(#\#):not(#\#) {
    background-color: #fff;
}
.x1ik0xcp:not(#\#):not(#\#):not(#\#) {
    box-shadow: 0 0 16px #0000001a;
}
.x3ja3p5:not(#\#):not(#\#):not(#\#) {
    color: #329b25;
}
.x1wzkho:not(#\#):not(#\#):not(#\#) {
    color: #ff6850;
    color: color(display-p3 1.04321 0.334712 0.217808);
    color: lch(64.2906% 106.837 40.8577);
}
.x195j60l:not(#\#):not(#\#):not(#\#) {
    color: var(--x1yjbm8s);
}
@media (max-width: 1024px) {
    .x1yewo9u.x1yewo9u:not(#\#):not(#\#):not(#\#) {
        color: purple;
    }
}

I think it's the last issue I found yet, thx for resolving!

nonzzz commented 6 months ago

Got it. I'll try to figure out what happened for this question. In my local env no matter mac/windows/WSL. If i using the ?url the final chunk is


const $style = 'base64 string' // the stackblitz is the real output path.

I'm not sure what happened on it.

predaytor commented 6 months ago

This is definitely not a priority issue. Using URL imports is quite useful for organizing styles if, say, you have multiple sources/components with separate stylesheets, which is not the case with StyleX. There seem to be other related benefits to using this type of import, such as pre-loading the stylesheet (not sure about the actual performance improvement) and a more ergonomic way of including the stylesheet that will be the same as in production. And for example, avoiding duplication of Vite dev server regarding side-effect css imports (https://github.com/remix-run/remix/issues/8830). All other things are working properly now, very thanks 🫡

nonzzz commented 6 months ago

Now i have time to resolve this question. The problem will be resolve at next version.

nonzzz commented 6 months ago

Now, 0.6.2 has been released. Try it.

predaytor commented 6 months ago

@nonzzz thank you! your example works perfectly! however, in local testing, there's an error I think related to rollup, it logs out about string offset for some reason:

> remix vite:build

vite v5.2.10 building for production...
Error in error handler:
Error: offset is longer than source length! offset 3305 > length 435
    at numberToPos (file:///Users/predaytor/projects/project-web/node_modules/.pnpm/vite@5.2.10_@types+node@20.12.7_lightningcss@1.24.1/node_modules/vite/dist/node/chunks/dep-DkOS1hkm.js:12460:15)
    at formatError (file:///Users/predaytor/projects/project-web/node_modules/.pnpm/vite@5.2.10_@types+node@20.12.7_lightningcss@1.24.1/node_modules/vite/dist/node/chunks/dep-DkOS1hkm.js:50839:35)
    at TransformContext.error (file:///Users/predaytor/projects/project-web/node_modules/.pnpm/vite@5.2.10_@types+node@20.12.7_lightningcss@1.24.1/node_modules/vite/dist/node/chunks/dep-DkOS1hkm.js:50818:19)
    at Object.transform (file:///Users/predaytor/projects/project-web/node_modules/.pnpm/vite@5.2.10_@types+node@20.12.7_lightningcss@1.24.1/node_modules/vite/dist/node/chunks/dep-DkOS1hkm.js:51136:25)
    at async getRouteModuleExports (/Users/predaytor/projects/project-web/node_modules/.pnpm/@remix-run+dev@2.9.1_@remix-run+react@2.9.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_types_iysvx43rcbfob76xx3csbno6cu/node_modules/@remix-run/dev/dist/vite/plugin.js:232:21)
    at async Object.transform (/Users/predaytor/projects/project-web/node_modules/.pnpm/@remix-run+dev@2.9.1_@remix-run+react@2.9.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_types_iysvx43rcbfob76xx3csbno6cu/node_modules/@remix-run/dev/dist/vite/plugin.js:781:29)
    at async transform (file:///Users/predaytor/projects/project-web/node_modules/.pnpm/rollup@4.15.0/node_modules/rollup/dist/es/shared/node-entry.js:18513:16)
    at async ModuleLoader.addModuleSource (file:///Users/predaytor/projects/project-web/node_modules/.pnpm/rollup@4.15.0/node_modules/rollup/dist/es/shared/node-entry.js:18729:36)

✓ 0 modules transformed.
x Build failed in 59ms
SyntaxError: [remix] /Users/predaytor/projects/project-web/app/routes/_app.history.tsx: unknown: Missing semicolon. (110:1)

  108 |         /* 84px → 128px */
  109 |         fluid15: 'clamp(5.25rem, 4.4643rem + 3.9286vi, 8rem)',
> 110 | } as const;
      |  ^
  111 |
  112 | export const sizes = stylex.defineVars({
  113 |         ...vars,
file: /Users/predaytor/projects/project-web/app/routes/_app.history.tsx?client-route=1:110:1

I created a Stackblitz repo with colors.stylex.ts added, the error occurs when starting to parse this file:

> remix vite:build

vite v5.2.10 building for production...
✓ 5 modules transformed.
x Build failed in 207ms
SyntaxError: [remix] /home/predaytor/remix-stylex/app/root.tsx: unknown: Missing semicolon. (16:1)

  14 |  blackA11: 'color(display-p3 0 0 0 / 0.9)',
  15 |  blackA12: 'color(display-p3 0 0 0 / 0.95)',
> 16 | } as const;
     |  ^
  17 |
  18 | const whiteA = {
  19 |  whiteA1: 'color(display-p3 1 1 1 / 0.05)',
file: /home/predaytor/remix-stylex/app/root.tsx?client-route=1:16:1
19 |    { rel: 'preload', href: $styles, as: 'style' },
20 |    // These should match the css preloads above to avoid css as render blocking resource
21 |    { rel: 'stylesheet', href: $styles }
   |                  ^
22 |  ]
23 |  
    at constructor (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:353:19)
    at Parser.raise (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:3277:19)
    at Parser.semicolon (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:3598:10)
    at Parser.parseVarStatement (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:12711:10)
    at Parser.parseStatementContent (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:12322:23)
    at Parser.parseStatementLike (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:12239:17)
    at Parser.parseModuleItem (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:12216:17)
    at Parser.parseBlockOrModuleBlockBody (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:12796:36)
    at Parser.parseBlockBody (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:12789:10)
    at Parser.parseProgram (file:///home/predaytor/remix-stylex/node_modules/.pnpm/@babel+parser@7.24.4/node_modules/@babel/parser/lib/index.js:12116:10) {
  code: 'PLUGIN_ERROR',
  reasonCode: 'MissingSemicolon',
  loc: Position { line: 16, column: 1, index: 585 },
  pos: 585,
  plugin: 'remix',
  id: '/home/predaytor/remix-stylex/app/root.tsx?client-route=1',
  pluginCode: 'import {\n' +
    '  Links,\n' +
    '  LiveReload,\n' +
    '  Meta,\n' +
    '  Outlet,\n' +
    '  Scripts,\n' +
    '  ScrollRestoration\n' +
    "} from '@remix-run/react'\n" +
    '\n' +
    "import type { LinksFunction } from '@remix-run/node'\n" +
    "import * as stylex from '@stylexjs/stylex';\n" +
    '\n' +
    "// import './styles/index.css'\n" +
    "import $styles from './styles/index.css?url'\n" +
    "import { colors } from '~/styles/colors.stylex'\n" +
    '\n' +
    'export const links: LinksFunction = () => [\n' +
    '  // Preload CSS as a resource to avoid render blocking\n' +
    "  { rel: 'preload', href: $styles, as: 'style' },\n" +
    '  // These should match the css preloads above to avoid css as render blocking resource\n' +
    "  { rel: 'stylesheet', href: $styles }\n" +
    ']\n' +
    '\n' +
    'export default function App() {\n' +
    '  return (\n' +
    '    <html lang="en">\n' +
    '      <head>\n' +
    '        <meta charSet="utf-8" />\n' +
    '        <meta name="viewport" content="width=device-width, initial-scale=1" />\n' +
    '        <Meta />\n' +
    '        <Links />\n' +
    '      </head>\n' +
    '      <body {...stylex.props(styles.body)}>\n' +
    '        <Outlet />\n' +
    '        <ScrollRestoration />\n' +
    '        <Scripts />\n' +
    '        <LiveReload />\n' +
    '      </body>\n' +
    '    </html>\n' +
    '  )\n' +
    '}\n' +
    '\n' +
    'const styles = stylex.create({\n' +
    '  body: {\n' +
    '    color: colors.foreground\n' +
    '  }\n' +
    '})',
  frame: "19 |    { rel: 'preload', href: $styles, as: 'style' },\n" +
    '20 |    // These should match the css preloads above to avoid css as render blocking resource\n' +
    "21 |    { rel: 'stylesheet', href: $styles }\n" +
    '   |                  ^\n' +
    '22 |  ]\n' +
    '23 |  ',
  hook: 'transform',
  watchFiles: [
    '/home/predaytor/remix-stylex/node_modules/.pnpm/@remix-run+dev@2.9.1_@remix-run+react@2.9.1_@remix-run+serve@2.9.1_lightningcss@1.24.1_typescript@5.4.5_vite@5.2.10/node_modules/@remix-run/dev/dist/config/defaults/entry.client.tsx',
    '/home/predaytor/remix-stylex/app/root.tsx',
    '/home/predaytor/remix-stylex/app/routes/_index.tsx',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/react@18.3.1/node_modules/react/jsx-runtime.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/@remix-run+react@2.9.1_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/@remix-run/react/dist/esm/index.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/react@18.3.1/node_modules/react/index.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/client.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/@remix-run+react@2.9.1_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/@remix-run/react/dist/esm/browser.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/@remix-run+react@2.9.1_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/@remix-run/react/dist/esm/components.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/@remix-run+react@2.9.1_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/@remix-run/react/dist/esm/scroll-restoration.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/@remix-run+react@2.9.1_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/@remix-run/react/dist/esm/server.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/react-router-dom@6.23.0_react-dom@18.3.1_react@18.3.1/node_modules/react-router-dom/dist/index.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/@remix-run+server-runtime@2.9.1_typescript@5.4.5/node_modules/@remix-run/server-runtime/dist/esm/index.js',
    '/home/predaytor/remix-stylex/node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react-jsx-runtime.production.min.js'
  ]
}
 ELIFECYCLE  Command failed with exit code 1.
nonzzz commented 6 months ago

It seems like as const cause it. I will fix them.

nonzzz commented 6 months ago

v0.6.3 has been released.

nonzzz commented 6 months ago

Any more problem? If not i'll close this.

predaytor commented 6 months ago

@nonzzz, everything is fine now, except there is another issue related to css import in main css file (only on production build, dev is fine). I updated Stackblitz.

/styles/index.css:

@import './reset.css' layer(core);

@custom-media --mx-1 (width <= 1024px);

@stylex-dev;
> remix vite:build

vite v5.2.10 building for production...
✓ 102 modules transformed.
x Build failed in 1.29s
Error: [stylex] ENOENT: no such file or directory, open '/home/predaytor/remix-stylex/reset.css'
    at Object.openSync (https://remixstylex-f5cr.w-credentialless-staticblitz.com/blitz.41fbae16.js:49:16217)
    at Object.readFileSync (https://remixstylex-f5cr.w-credentialless-staticblitz.com/blitz.41fbae16.js:49:17820)
    at read (file:///home/predaytor/remix-stylex/node_modules/.pnpm/vite@5.2.10_lightningcss@1.24.1/node_modules/vite/dist/node/chunks/dep-DkOS1hkm.js:33285:44)
    at napi_call_function (file:///home/predaytor/remix-stylex/node_modules/.pnpm/lightningcss@1.24.1/node_modules/lightningcss/node_modules/napi-wasm/index.mjs:752:20)
    at wasm://wasm/02920906:wasm-function[4360]:0x998627
    at wasm://wasm/02920906:wasm-function[4351]:0x9948fe
    at wasm://wasm/02920906:wasm-function[4365]:0x99aba6
    at wasm://wasm/02920906:wasm-function[4375]:0x99daa9
    at wasm://wasm/02920906:wasm-function[4365]:0x99b2d6
    at wasm://wasm/02920906:wasm-function[4351]:0x9958c7 {
  syscall: 'open',
  errno: -2,
  code: 'PLUGIN_ERROR',
  path: '/home/predaytor/remix-stylex/reset.css',
  fileName: '@stylex-dev.css',
  loc: { line: 1, column: 1 },
  data: 'ResolverError',
  pluginCode: 'ENOENT',
  plugin: 'stylex',
  hook: 'renderChunk'
}
 ELIFECYCLE  Command failed with exit code 1.
nonzzz commented 6 months ago

It seems like vite can't handle virtual css file with import source, I do a hack in my local make it works well, vite is so magic 😂

predaytor commented 6 months ago

thx!

nonzzz commented 6 months ago

v0.6.4 released. All test be pass now

predaytor commented 6 months ago

unfortunately have found another 🐞 in production build (dev is fine). It is unclear to determine where issue coming from, but it seems related to assets resolving. Stackblitz.

After importing fonts.css file, the css output is not complete:

/styles/index.css:

@import './reset.css' layer(core);
@import './fonts.css' layer(core);

@custom-media --mx-1 (width <= 1024px);

@stylex-dev;

Logs:

> remix vite:build

vite v5.2.10 building for production...
✓ 90 modules transformed.
build/client/.vite/manifest.json                1.70 kB │ gzip:  0.47 kB
build/client/assets/index-H7vdUXJC.css          0.19 kB │ gzip:  0.18 kB
build/client/assets/_index-BFlo-OSt.js          0.64 kB │ gzip:  0.43 kB
build/client/assets/stylex-Ch64yUrd.js          1.45 kB │ gzip:  0.81 kB
build/client/assets/root-CPgZHOb1.js            1.57 kB │ gzip:  0.93 kB
build/client/assets/jsx-runtime-56DGgGmo.js     8.11 kB │ gzip:  3.06 kB
build/client/assets/entry.client-zrxhHt8n.js   11.40 kB │ gzip:  4.08 kB
build/client/assets/components-CcSf4wyG.js    224.73 kB │ gzip: 72.69 kB
✓ built in 2.56s
vite v5.2.10 building SSR bundle for production...
"create" is imported from external module "@stylexjs/stylex" but never used in "app/styles/colors.stylex.ts", "app/root.tsx", "app/theme.stylex.ts", "app/Card.tsx" and "app/routes/_index.tsx".
✓ 10 modules transformed.
build/server/.vite/manifest.json        0.32 kB
build/server/assets/index-H7vdUXJC.css  0.19 kB
build/server/index.js                   7.58 kB
✓ built in 156ms

css output:

@layer core{*{box-sizing:border-box}@font-face{font-family:Open Sans;font-style:normal;font-weight:400 700;font-stretch:100%;font-display:swap;src:url(__VITE_PUBLIC_ASSET__ec4b305e__)format(\

If we comment out fonts.css string, everything works fine, both in dev/prod. Thank you for taking the time to resolve these issues.

> remix vite:build

vite v5.2.10 building for production...
✓ 90 modules transformed.
build/client/.vite/manifest.json                1.70 kB │ gzip:  0.46 kB
build/client/assets/index-Cx71Aqqp.css         55.65 kB │ gzip:  9.92 kB
build/client/assets/_index-BFlo-OSt.js          0.64 kB │ gzip:  0.43 kB
build/client/assets/stylex-Ch64yUrd.js          1.45 kB │ gzip:  0.81 kB
build/client/assets/root-RalocTlt.js            1.57 kB │ gzip:  0.93 kB
build/client/assets/jsx-runtime-56DGgGmo.js     8.11 kB │ gzip:  3.06 kB
build/client/assets/entry.client-zrxhHt8n.js   11.40 kB │ gzip:  4.08 kB
build/client/assets/components-CcSf4wyG.js    224.73 kB │ gzip: 72.69 kB
✓ built in 1.80s
vite v5.2.10 building SSR bundle for production...
"create" is imported from external module "@stylexjs/stylex" but never used in "app/styles/colors.stylex.ts", "app/root.tsx", "app/theme.stylex.ts", "app/Card.tsx" and "app/routes/_index.tsx".
✓ 10 modules transformed.
build/server/.vite/manifest.json         0.32 kB
build/server/assets/index-Cx71Aqqp.css  55.65 kB
build/server/index.js                    7.58 kB
✓ built in 151ms
nonzzz commented 6 months ago

I think all problem is fixed onv0.7.0

predaytor commented 6 months ago

seems to be fine. thanks!