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

add an option to not to inline assets in library mode when format is 'es' #4454

Open
4 tasks done
hronro opened this issue Jul 31, 2021 · 34 comments · May be fixed by #9734
Open
4 tasks done

add an option to not to inline assets in library mode when format is 'es' #4454

hronro opened this issue Jul 31, 2021 · 34 comments · May be fixed by #9734
Labels
contribution welcome feat: library mode p2-nice-to-have Not breaking anything but nice to have (priority)

Comments

@hronro
Copy link
Contributor

hronro commented Jul 31, 2021

Clear and concise description of the problem

Currently when using library mode, all the assets (images, videos...) are inlined using base64. When those assets are big, it takes a long for vite to build, and the browser also takes a long time to parse the javascript.

Suggested solution

When the library format is 'es', we can add an option to make vite emit those files, and import those files in javascript using new URL(import.meta.url, '...'), e.g.

import foo from './image.png';

const bar = foo; // new URL(import.meta.url, './assets/image.2d8efhg.png')

Alternative

No response

Additional context

No response

Validations

@xesjkeee
Copy link

+1 for that feature,

In my case, I want to build a components library that includes fonts with that option, but now Vite includes the fonts in base64 string, after build, I see that my style.css: dist/style.css 1067.79 KiB / brotli: skipped (large chunk)

These are so huge for CSS and every new update of my CSS will be recached old file, but fonts are a more stable thing in the library and I can cache them for long days unlike style.css

@Shinigami92 Shinigami92 added p2-nice-to-have Not breaking anything but nice to have (priority) and removed enhancement: pending triage labels Aug 27, 2021
@patak-dev
Copy link
Member

@xesjkeee would you create another feature request for avoiding bundling the fonts in css files? Your proposal is a good idea to explore but it isn't directly related to this issue. Thanks!

@patak-dev
Copy link
Member

@hronro we discussed your proposal with the team and it sounds good. As you said, it should only be applied to es, and lib mode should still bundle the assets for other configured formats. Adding the contribution welcome to this issue in case someone wants to work on this issue.

@github-actions
Copy link

Hello @hronro. We like your proposal/feedback and would appreciate a contribution via a Pull Request by you or another community member. We thank you in advance for your contribution and are looking forward to reviewing it!

@torsteinringnes
Copy link

Besides from checking es, this might help getting your assets emitted:
#3295 (comment)

@pleek91
Copy link

pleek91 commented Nov 8, 2021

Is this going to be fixed? I see the PR was closed and wondering if this issue is still something the maintainers want to fix. I have a library built with vite that has an icon font. I'd rather not have the font inlined in css as that makes for a very large css file and effectively means those files can't be cached long term.

It also means the browser is downloading all 3 font formats provided when it only needs to download the one it can/will use which is very inefficient.

@franktopel
Copy link

franktopel commented Nov 30, 2021

I also need this urgently, as we're about to launch our component library built with Vite, and our security engineer doesn't want us to allow data: for font-src or image-src in our Content-Security-Policy.

Please upgrade the relevance of this feature as without it, people are forced to implement an inherently insecure setting for their Content-Security-Policy!

@artemtam
Copy link

Are there any updates on that? It seems like a very common use-case for libraries – barely anyone wants fonts to be inlined in CSS.

@kaokei
Copy link

kaokei commented Apr 4, 2022

I initialized a monorepo by rush recently. The monorepo has a vue app package and a vue component package.

The key problem is the vue component package depend on a logo image. The key code is as below.

import logo from './assets/logo.png';

<img :src="logo" alt="logo"/>

First time I use vue build --target lib to build the vue component package. I found that vue cli only support commonjs and umd. Though the vue app package can import the vue component package correctly. But the vue app package cannot find the logo image.

I have checked the vue component package's compiled code. The key code is as below.

module.exports = __webpack_require__.p + "img/logo.c83cee16.png";

So I guess webpack inside vue app package cannot detect the compiled vue component package depend on a logo png.

Second time I changed to use vite to build the vue component package. And vite document said that it supports es and umd.
So I thought webpack inside vue app package can detect the compiled(es code) vue component package depend on a logo png.

But finally I find this issue. Vite inline all assets in library mode. 😢

So as a summary, we cannot use any image or other assets inside vue component.
Vue cli will cause vue app cannot find the image.
Vite seems work properly, But vite inline all assets into js file.

@g10
Copy link

g10 commented May 19, 2022

…this works for css…

assets in public folder

public/fonts/Font.otf

in css, ./ dot prefix the path

@font-face {
  src: url("./fonts/Font.otf") format("opentype");
}

in vite.config, build lib with es format

  build: {
    lib: {
      formats: ["es"],
      …
    },
   outDir: "./lib",
   …

the public folder content is copied to lib and paths in css are preserved → no inline assets

package.json

  …
  "files": [
    "lib/*",
    …
  ],
  "exports": {
    ".": {
      "import": "./lib/index.es.js"
    },
    "./style.css": "./lib/style.css"
    …
  },

@LizAinslie
Copy link

This would be amazing to have, for situations like the one I'm facing where I have a monorepo, with a shared codebase for frontend app logic and a web app and a separate electron app that both render that same shared codebase

@bencun
Copy link

bencun commented Oct 4, 2022

What @g10 suggested worked like a charm for the lib we're working on.

Placing files in public folder and referencing them with an absolute path worked great in my case (font files).
But, make sure to update your vite.config.ts with the following or otherwise it won't work

   root: './',
   publicDir: 'public',

@ZKHelloworld
Copy link

Looking forward to have this option supported.

We are currently working on a library including a large webassembly file(10M plus).
It's not possible to publish this library as a single JS file bundling with out wasm file.

@agileago
Copy link

agileago commented Jan 3, 2023

+1

@ManBearTM
Copy link

I have found https://github.com/ManBearTM/vite-plugin-no-bundle, but was unable to make it work.

As the author of that plugin, I would love to know more about the issues you encountered so that I may attempt to fix them 🙂

The plugin does something very much like your solution, but it goes even further and doesn’t actually bundle anything - so unless you want that, it is probably not a good fit.

Also, the plugin does not aim to resolve the problem in this issue, though it does have a copy option that simply marks local files as external and then copies the raw files to the build folder. But this only works for simple use cases where you don’t need Vite to touch the files at all.

@ZKHelloworld
Copy link

I wrote a plugin to "external" assets in library mode:
https://gist.github.com/ZKHelloworld/4d518583b90ddcb4762d49c102a42054

usage:

    plugins: [
      viteLibraryAssetExternal({
        test: /.*(png|jpg|jpeg)$/, // assets to external
        include: ['.ts', '.tsx', '.js', '.jsx'], // source file to check
        dir: 'assets' // output directory for assets
      }),
    ],

@garygreen
Copy link

Pretty significant that Vite doesn't have this feature yet. Webpack had file-loader since v0.5 which was able to emit external files (font files, svgs, jpegs, etcs) without having to inline them in CSS, etc. Hoping this gets some love soon! 😀

@fanlion
Copy link

fanlion commented Apr 20, 2023

This would be amazing to have, for situations like the one I'm facing where I have a monorepo, with a shared codebase for frontend app logic and a web app and a separate electron app that both render that same shared codebase

I had the same problem, I tried to compile a vue3 project and keep the directory structure, publish to npm repository. I split a project into monorepo. no idea yet

@BonjourYY
Copy link

This problem has been bothering me for a long time. Is there any update?

@rajsite rajsite mentioned this issue May 8, 2023
1 task
@grybykm
Copy link

grybykm commented Jun 12, 2023

Any updates on the issue? Can't start using vite because of that. Thank you!

@jonaskuske
Copy link
Contributor

@grybykm Feel free to comment on my RFC with your use case: #13172

@grybykm
Copy link

grybykm commented Jun 13, 2023

Thank you!

In meanwhile I've managed to workaround by using rollupOptions.external feature and using vite-plugin-static-copy plugin. I have to manually specify every file I want to use as url, ex './my-icons.svg?url' and then copying it with vite-plugin-static-copy.

@adonaicandido
Copy link

adonaicandido commented Jun 21, 2023

I have a monorepository with several UI libraries in react used by applications outside this monorepository.

What would be the simplest workaround for a use case where I use images, fonts and videos from within the same library? I thought about leaving the files in the public folder, and in the application, changing the path of the public folder to node_modules/@my-org/my-lib/assets, but then I would need to create another assets folder inside public, otherwise when building the library folders inside public will go to the root of the outDir, and the vite public folder configuration parameter only accepts a single string and that would prevent the application from adding more files.

I remember reading somewhere that maybe using an exclusive package for these assets might work, but I don't understand how.

@coder-layne
Copy link

https://github.com/vitejs/rfcs/discussions/16

I wrote a plugin to emit external files in library mode: vite-plugin-lib-assets

@DenizUgur
Copy link

Using the following syntax manages to create seperate file for each asset but it modularizes them and in doing so it encodes them in base64 again. Extra steps for the same thing?

foo.js here is emscripten generated file so it needs to be treated as an asset

await import("../bin/foo.js?url").then(m => m.default)

Weirdly enough, I have a worker file that's being imported in the following syntax. That however, places the related worker file under assets/ directory and loads it via absolute path.

import FooWorker from "./worker?worker&url"

new Worker(new URL(FooWorker, import.meta.url).href, {
  type: "module"
})

Now, to an extent I could understand why library mode differs from standalone mode. However, within same mode why does this asset bundling differ? Either putting the worker under assets was a mistake or this is possible from the start but the first syntax I've pointed out is being neglected. Or there is another syntax which would work in the same way as how workers are being bundled.

If someone could shine a light on this that would be delightful.

@zgrybus
Copy link

zgrybus commented Mar 25, 2024

Have the same problem, but with an external library. I am using KaTeX in my project, and it has around 1.2 MB of fonts. When compiled as library, every font gets included into a single style.css, and it grows to a size of 1.5 MB.

I have tried the public workaround above, setting it to node_modules/katex/dist/fonts, however it did not work: fonts were copied into the dist folder, but style.css still inlined all of them.

EDIT: I would have assumed that setting build.assetsInlineLimit to 0 would work, but it did not -- assets are still inlined.

EDIT 2: I have resorted to adding ["katex", /katex\/dist/] (yes, both) to build.rollupOptions.external and moving katex to peerDependencies, but this is really not ideal. Would love this to be fixed ASAP. PR #9734 seems to be abandoned though, and no maintainers have even left a comment there.

@rijenkii Have you managed to do something with that? I've noticed that we have exactly the same problem that you mentioned :/

@rijenkii
Copy link

@zgrybus Well, kind of, but not really. Currently using something like this:

import pkg from "./package.json";

const deps = [...Object.keys(pkg.dependencies), ...Object.keys(pkg.peerDependencies)];

export default defineConfig({
  build: {
    rollupOptions: {
      external: (source) => {
        for (const dep of deps) {
          if (source === dep || source.startsWith(`${dep}/`)) {
            return true;
          }
        }
        return false;
      },
    },
  },
});

This allows the usage of aliases, but may fail if you accidentally import something from a transitive dependency that is not explicitly defined in the package.json.

@psychobolt
Copy link
Contributor

psychobolt commented Sep 19, 2024

My setup consist of two Vite build configs. Ended up disabling lib mode and using rollupOptions as a workaround for me. This is currently in my config for asset files:

export default defineConfig({
  build: {
    lib: false,
    rollupOptions: {
      input: { /* ...assets */ },
      output: {
          assetFileNames: ({ name }) =>
            name ? name : 'assets/[name]-[hash][extname]'
      }
    },
  },
});

And then I have another config for the non assets, making sure I correctly alias the paths to the asset build files. As long you don't bundle those files into your JS, you're good to go...

@marcofugaro
Copy link

marcofugaro commented Jan 13, 2025

Still having this problem in 2025, I am trying to make vite not inline a .wasm file outputted by wasm-pack.
Reason is the binary .wasm file gets obviously too big when inlined.
rollupOptions.external has no effect.

@Nearoo
Copy link

Nearoo commented Jan 16, 2025

@marcofugaro There's a way with vite 6:

  • import wasmUrl from "../foo.wasm?no-inline in your ts file
  • assetsInclude: ["**/*.wasm"] into vite.config.mts

This method doesn't work for js files though. Importing a js file using ?no-inline imports it like a regular javascript module. There seems to be no way to combine ?url & ?no-inline, which we need to import wasm wrapper code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution welcome feat: library mode p2-nice-to-have Not breaking anything but nice to have (priority)
Projects
None yet
Development

Successfully merging a pull request may close this issue.