pngwn / MDsveX

A markdown preprocessor for Svelte.
https://mdsvex.pngwn.io
MIT License
2.3k stars 96 forks source link

Svelte 4 interpret CSS code import #528

Open peterpeterparker opened 1 year ago

peterpeterparker commented 1 year ago

Hi,

In one of our pages or our UI library we display following block of code that contains a Scss import.

` ` `html
<style lang="scss" global>
  @import "@dfinity/gix-components/styles/global.scss";
</style>
` ` `

When building with Svelte v3 we do not get any error and block is generated as expected. However, when we try to build with Svelte v4, it seems that the block of code becomes an effective code that Svelte tries to build because we get following error:

vite v4.3.9 building SSR bundle for production... ✓ 12 modules transformed. ✓ built in 492ms [vite-plugin-svelte] Error while preprocessing /Users/.../dfinity/gix-components/src/routes/(page)/styling/usage/+page.md - Can't find stylesheet to import. ╷ 2 │ @import "@dfinity/gix-components/styles/global.scss"; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ╵ src/routes/(page)/styling/usage/+page.md 2:11 root stylesheet file: /Users/daviddalbusco/projects/dfinity/gix-components/src/routes/(page)/styling/usage/+page.md error during build: Error: Can't find stylesheet to import. ╷ 2 │ @import "@dfinity/gix-components/styles/global.scss";

Not sure if it's a bug per sé or anything that can be done on our side to prevent Svelte v4 to intepret the documented code as effective code?

thnee commented 4 months ago

Well, this was certainly an annoying and confusing bug. Especially since everything seemed to work fine with the dev server, but breaks badly in production build.


Given this source code:

There is this output in dev mode:

<style>
body {background: red !important;}
</style>

But there is this output in production build mode:

<style>body{background:red!important}</style>

If I add a language to the beginning of the code fence like this:

```html

Then the output is colored with syntax highlighting in both modes, but the spaces are still removed in production build mode as shown above.


Given this source code:

There is this output in dev mode:

<style>
  // A comment
  .something {color: red;}
</style>

But during production build, there is a crash with this error:

Error ``` error during build: SyntaxError: Error while preprocessing /path/to/src/lib/articles/my-article.md - Invalid empty selector at OnceExit (/path/to/node_modules/postcss-lightningcss/src/index.js:37:23) at LazyResult.runAsync (/path/to/node_modules/postcss/lib/lazy-result.js:298:21) at async process (/path/to/node_modules/svelte-preprocess/dist/transformers/postcss.js:32:36) at async style (/path/to/node_modules/svelte-preprocess/dist/autoProcess.js:179:37) at async process_single_tag (file:///path/to/node_modules/svelte/src/compiler/preprocess/index.js:280:21) at async Promise.all (index 0) at async replace_in_code (file:///path/to/node_modules/svelte/src/compiler/preprocess/replace_in_code.js:69:23) at async process_tag (file:///path/to/node_modules/svelte/src/compiler/preprocess/index.js:297:26) at async Module.preprocess (file:///path/to/node_modules/svelte/src/compiler/preprocess/index.js:361:25) at async compileSvelte (file:///path/to/node_modules/@sveltejs/vite-plugin-svelte/src/utils/compile.js:96:20) ```

So it seems like this source code is being "picked up" in an undesired way by the postcss and/or lightningcss compilers/tools.

I also tried disabling lightningcss, but it's clear that the code is still processed in an undesirable way by postcss alone. The output is still somewhat mangled, some spaces are removed.

It seems like the solution here should be to have MDsveX somehow say that this piece of source code is "marked as verbatim" so that it doesn't get picked up by any part of the compiler toolchain. In order to that, one would also have to guarantee that MDsveX runs before those other compilers/tools.

I've seen solutions like that in other frameworks before. For example the verbatim tag in Django. But I have no idea how to do that in Svelte(Kit).

Details about installed packages and configuration **package.json** ``` "devDependencies": { "@sveltejs/adapter-static": "^3.0.1", "@sveltejs/kit": "^2.5.5", "@sveltejs/vite-plugin-svelte": "^3.0.2", "@tailwindcss/forms": "^0.5.7", "mdsvex": "^0.11.0", "postcss": "^8.4.38", "postcss-lightningcss": "^1.0.0", "postcss-preset-env": "^9.5.2", "svelte": "^5.0.0-next.87", "svelte-preprocess": "^5.1.3", "tailwindcss": "^3.4.3", "vite": "^5.2.7" } ``` **routes/+layout.js** ```js export const prerender = true; export const ssr = true; ``` **postcss.config.js** ```js import path from "path"; import { fileURLToPath } from "url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export default (ctx) => { let lightningcss = false; if (ctx.env === "production") { lightningcss = {}; } return { plugins: { "tailwindcss/nesting": {}, "tailwindcss": path.resolve(__dirname, "./tailwind.config.js"), "postcss-import": {}, "postcss-preset-env": {}, "postcss-lightningcss": lightningcss, }, }; }; ```

But I managed to workaround the problem by escaping the tags in the source code, like this:

\<style> // A comment .something {color: red;}

I have no idea how safe this is, or if it will work for any inner code, but it seems to work fine so far.