sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
17.96k stars 1.8k forks source link

build single js file and single css file like Svelte does. #3882

Open kauaicreative opened 2 years ago

kauaicreative commented 2 years ago

Describe the problem

Is there an option or an adaptor that will build the app as svelte does - with a single js file and single css file?

Describe the proposed solution

This makes embedding into wordpress much simpler.

Alternatives considered

I am using the adapter from '@sveltejs/adapter-static' but this builds each component into many individual js and css files. Also tried the wordpress adapter. It is not compatible with the latest version of Svelte Kit. And I do not believe it will create a single js file and single css file.

Importance

i cannot use SvelteKit without it

Additional Information

No response

kauaicreative commented 2 years ago

I see that using adapter( { fallback: 'index.html' }) get's me most the way there - 2 js file and 1 css file. But the file names change after each compilation (/_app/assets/vendor-4ff902fe.css") which makes linking to these files impossible without another build step. Is there a way to set the file name much like we can set the pages and assets directory names?

    <link rel="stylesheet" href="/_app/assets/vendor-4ff902fe.css">
    <link rel="modulepreload" href="/_app/start-7cbc46f1.js">
    <link rel="modulepreload" href="/_app/chunks/vendor-878788bc.js">
benmccann commented 2 years ago

You may be interested in the inlineStyleThreshold option: https://kit.svelte.dev/docs/configuration#inlinestylethreshold

The name is based on the file contents. This allows the file to be cached. Can you explain more about why you would want to link to these files?

kauaicreative commented 2 years ago

@benblazak , thanks for the idea but I don't think it will work in this case.

I have several svelte apps which I am dynamically inserting into wordpress content via shortcodes. In wordpress/php I wp_register_script() and wp_enqueue_script() to add the css and js assets to the wordpress page render process. These filenames can not change. I then insert the svelte startup markup into the content. e.g. svelte: <div id="app"></div> , or sveltekit: start({...})

I was hoping to use sveltekit moving forward but I may have to go back to svelte for these embedded apps.

kauaicreative commented 2 years ago

Wondering if I should be looking at component packaging instead https://github.com/sveltejs/kit/issues/518 https://github.com/sveltejs/kit/pull/1499

gevera commented 1 year ago

Encountered same need, we are transitioning from a React SPA. Hopefully this will get some love

cubic3d commented 1 year ago

@gevera looks like you can use vite config to influence file names: https://github.com/sveltejs/vite-plugin-svelte/issues/375#issuecomment-1156609925

paolodina commented 1 year ago

@cubic3d

I tried and doesn't work.

The following Vite config options will be overridden by SvelteKit:
  - build.rollupOptions.output.entryFileNames
  - build.rollupOptions.output.chunkFileNames
  - build.rollupOptions.output.assetFileNames
edwinspire commented 1 year ago

I have the same problem with the latest version of Svelte.

d-velopment commented 1 year ago

While there's no solution or adapter itself hasn't been improved, I've created the "hacky" way of re-wrapping the project files to the bundle.js: https://github.com/d-velopment/SvelteKit-One-Bundle

It's not solving the problem of thousand chunks but gives the bundle.js to be loaded from a custom index.html or another project to render the application.

benmccann commented 1 year ago

Can folks share their use cases for this? If we implement it, I'd like to ensure that we document when to use it vs when not to. I believe users should mostly avoid this option, but I'd like to hear about valid use cases so that we can guide users appropriately.

wozzashek commented 1 year ago

My use case is for an enterprise platform. In truth I don't need all the JS to be in a single file. Rather I need all the JS to be built to the /dist folder, no JS or CSS in subfolders.

So the enterprise platform I use allows me to serve a single html page at an endpoint with all JS & CSS file requests coming from that endpoint e.g.

Index html: platform.com/webapp/my_app All JS/CSS files: platform.com/webapp/my_app/{filename}

Although that forces me to use hashed routing as well which I guess I'll have to implement myself unless Sveltekit has one I can turn on.

khromov commented 1 year ago

@benmccann I'm making a Capacitor application for iOS/Android. Capacitor works by starting a local web server and then serving your application like a static host on your phone. This local server does not have SSL or HTTP/2, so while some requests load in parallel, it takes quite a while to load 50+ resources over HTTP/1. It's hard to measure raw numbers but in our project it takes around ~1 second for loading up the app until interactable and about half that on our PWA version. So it takes twice as long to load a local application on your phone than going to servers in a different country.

edwinspire commented 1 year ago

In my case I am using svelte to create a web interface inside an ESP32 (microcontroller), for the microcontroller, the fewer requests it has to attend to, the better, for this reason having everything in one file is ideal, or at least the html, js and css are each in a single file.

ChristianSch commented 1 year ago

This is also a common problem highlighted by SEO tools. 'reduce number of css files'. Would be good to be able to combine them.

anakinjay commented 1 year ago

I have this need for importing components into other systems like wordpress or drupal.

In react, we've always handled this by reading the assets manifest.json file from webpack to figure out which file names we need to load, which vite DOES support under the options build.manifest, but when I try and enable that settings I get the error:

The following Vite config options will be overridden by SvelteKit:
  - build.manifest
mdocter commented 1 year ago

Like @wozzashek mentioned, I also work with an enterprise system, Microsoft Dynamics/Power Platform.

  1. In their case Microsoft prepends a cache busting version value (=hash/guid) in front of my web files in the url path. So a hash in the js/css filenames is unnecessary.

<Microsoft Dynamics URL>/%7B<version value>%7D/WebResources/index.html

  1. Those web resources are part of a solution zip file which is used to deploy and redeploy updates. So I want to have the same file names, otherwise my solution grows and grows with each build being added.

I tried all suggestions to disable the [hash] in the file names, but nothing works. Having multiple chunks is not a problem in my use case, as long as they have the same file names.

Any suggestions on how to disable the hash in the file names?

tystol commented 1 year ago

My use case is for packaging up an admin front-end UI within a back-end library. The devs consuming the library will ultimately choose which paths the UI will be served under, and it needs to be dynamic at runtime. eg. The Hangfire dashboard UI (not my project, but a close analogy to what I need to do): https://docs.hangfire.io/en/latest/configuration/using-dashboard.html Note the end of the article, I'd like to support things like this too:

Multiple DashboardsΒΆ You can also map multiple dashboards that show information about different storages.

var storage1 = new SqlServerStorage("Connection1"); var storage2 = new SqlServerStorage("Connection2");

app.UseHangfireDashboard("/hangfire1", new DashboardOptions(), storage1); app.UseHangfireDashboard("/hangfire2", new DashboardOptions(), storage2);

captainhusaynpenguin commented 10 months ago

My most obvious usecase is developing a CSS framework and using SvelteKit as a wrapper for documentations and also partially custom implementation of the CSS style for one off svelte components.

So, such a feature would be extremely, extremely appreciated;

PS. Stuff like these seemed to be the focus/concern of the dev team at some point in time? see: Svelte.Dev Blog CSS-in-JS

mdocter commented 10 months ago

@benmccann Any updates on this topic?

migbash commented 10 months ago

We need this solution in sveltelkit as well, as we have a domain issue restriction with the amount of Page Resources loaded, and need to minimize the number of resources Goolge-Bot needs to load.

The current solution, that we have identified that works as intended for CSS, is to use the following setup, using

https://www.npmjs.com/package/vite-plugin-css-injected-by-js

πŸ“Œ src/app.html

[...]

<link
  rel="preload"
  href="/all-css-chunk.css"
  as="style"
/>
<link
  rel="stylesheet"
  type="text/css"
  href="/all-css-chunk.css"
/>

[...]
πŸ“Œ  vite.config.ts

import { defineConfig } from 'vitest/config';
import { sveltekit } from '@sveltejs/kit/vite';
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";
import fs from 'fs';

[...]

plugins:
[
  sveltekit(),

  // ### WARNING:
  // ### 'this' plugin removes all 'CSS' from standard
  // ### importing by 'svelte/svelteki' and styles will be missing
  // ### if not imported as a '<link ... >' in the 'src/app.html'
  cssInjectedByJsPlugin
  (
    {
      // ### NOTE:
      // ### definitive 'hack' solution for 'single CSS file' output chunk.
      injectCode:
      (
        cssCode,
        options
      ) =>
      {

        // ### NOTE:
        // ### the 'cssCode' generated contains some 'formatting' issues.
        // ### 1. remove 1st and last speech marks.
        // ### 2. remove cases of `\n` chars.
        // ### 3. correct custom-cases of ids/classes using the 'forward-slash' in the html declaration.
        let cssCodeMod: string = cssCode.slice(1, -1);
        cssCodeMod = cssCodeMod.replace(/\\n/g, "");
        cssCodeMod = cssCodeMod.replace(/\\\\/g,"\\")

        // ### WARNING:
        // ### 'all-css-chunk.css' must exist inside '/static'
        fs.writeFile
        (
          './static/all-css-chunk.css',
          cssCodeMod,
          err =>
          {
            if (err) console.error(err);
          }
        );

        return '';            
      }

    }
  ),

[...]

Warning The only issue with this that has been detected, is that the <style> from the src/routes/+layout.svelte file are not present in the all-css-chunk.css output, but every other <style> is present in the final chunk.

Beyondo commented 10 months ago

No single js files? This destroys user-experience. The latency between requests is just too much for any clients running below 3G. Be it microcontrollers like already mentioned or just generally bad connections which happen to everyone at some point. I think I'd just use Svelte for now.

edwinspire commented 10 months ago

No single js files? This destroys SEO. The latency between requests is just too much for any clients running below 3G. Be it microcontrollers like already mentioned or just generally bad connections which happen to everyone at some point. I think I'd just use Svelte for now.

I disagree with what you expose, I have been working with microcontrollers for a long time, where the number of concurrent connections is very limited and saturates the memory to the point of restarting the device. However, when I have a single file, the operation is the most optimal.

Beyondo commented 10 months ago

No single js files? This destroys SEO. The latency between requests is just too much for any clients running below 3G. Be it microcontrollers like already mentioned or just generally bad connections which happen to everyone at some point. I think I'd just use Svelte for now.

I disagree with what you expose, I have been working with microcontrollers for a long time, where the number of concurrent connections is very limited and saturates the memory to the point of restarting the device. However, when I have a single file, the operation is the most optimal.

Did you even read my comment properly? That's literally what I said. SvelteKit is bad for this kind of stuff. And you are not the only one working with microcontrollers as I've been running my own camera surveillance for years.

khromov commented 10 months ago

@Beyondo

No single js files? This destroys SEO.

This is false. In fact multiple JS files make the page appear faster because the browser has time to render things between JS files instead of rendering one huge blocking JS chunk.

The latency between requests is just too much for any clients running below 3G.

This is debatable. If you analyze a waterfall diagram you'll see that most requests load in parallel, it's not a chain of 30 requests one after another. When testing my latest project on https://web.dev/measure/ it got 99/100 in performance, when using simulated 4G slowdown. So Google does not seem to think there is any issue with the current approach.

Beyondo commented 10 months ago

@Beyondo

No single js files? This destroys SEO.

This is false. In fact multiple JS files make the page appear faster because the browser has time to render things between JS files instead of rendering one huge blocking JS chunk.

The latency between requests is just too much for any clients running below 3G.

This is debatable. If you analyze a waterfall diagram you'll see that most requests load in parallel, it's not a chain of 30 requests one after another. When testing my latest project on https://web.dev/measure/ it got 99/100 in performance, when using simulated 4G slowdown. So Google does not seem to think there is any issue with the current approach.

I disagree. This is not "false". You are saying that because some clients load the files in parallel or have a guaranteed connection, it is justifiable to literally divide the website into these horrible chunks? Your simulated slowdown is different from real-world slowdown. And I realized this is the hard way.

In an actual slow network scenario, it is not merely a matter of "bandwidth throttling" as commonly emulated in our development tools and all requests just 100% succeed after only a longer time like in your Google tests. No. In the real world, a sluggish network means any request could be dropped at any time.

Division of our SvelteKit website into numerous requests is nightmarish, as it poses the risk of any of these requests being dropped, which causes the site to cease functioning correctly or rendering appropriately. In my humble opinion, SvelteKit remains unsuitable for many projects (or at least not favorable).

khromov commented 10 months ago

I disagree. This is not "false".

The "This destroys SEO." part is false. I said that the latency part (which is what your post is about) is debatable.

If you are worried about poor connectivity, you can implement a service worker. Requests can always be dropped, but with HTTP/2 multiplexing, multiple requests are handled in the same stream, so the chances are reduces since you are not creating one connection per request.

I think the problem from your argument comes from your spreading FUD ("learned the hard way", "nightmarish") as opposed to trying to have a fact-based discussion. I am in favor of being able to build just one output file, but it's not for the reasons you suggested.

Beyondo commented 10 months ago

I disagree. This is not "false".

The "This destroys SEO." part is false. I said that the latency part (which is what your post is about) is debatable.

If you are worried about poor connectivity, you can implement a service worker. Requests can always be dropped, but with HTTP/2 multiplexing, multiple requests are handled in the same stream, so the chances are reduces since you are not creating one connection per request.

I think the problem from your argument comes from your spreading FUD ("learned the hard way", "nightmarish") as opposed to trying to have a fact-based discussion. I am in favor of being able to build just one output file, but it's not for the reasons you suggested.

Wow I'm sorry this is my typo. I meant user-experience and was talking about user-experience for the entirety of my two comments if you noticed. I didn't mean to say 'SEO' in my first comment and didn't even see it at all till you just mentioned it now. I edited it, you can check it again.

I'm honestly deeply sorry for this confusion. I never claimed my opinion as a "fact-based" either but actually said it is in my humble opinion to have one output file just like you said you favor them too.

In any case, I'd like to politely note that your premise that "chunky js files" are slower is not true but is that they actually they load faster (if not the same) since not only are they streamed straightforwardly in a single request, but you can always load them asynchronously (without waiting) while showing any pretty splash-screen for a few milliseconds before your layout loads to not have any layout shift. Of course this is just a design choice, like maybe splash screens aren't you thing, but again IMHO, they're much better than plain white backgrounds waiting for tens of preloaded scripts, and it gives the illusion that your app instantly loaded. Paired with a service worker for caching & some versioning, and any new updates would force the user to redownload the scripts making your app instant and versatile.

But it's not like this is new knowledge, single output files have always been favored by almost everyone. So although we both have might have different (or maybe overlapping) uses for a single chunky output, we both give legitimate reasons nonetheless or edge cases for own specific apps; it is not like Svelte is built only for a specific set of websites, but for all kind of web apps. So I might be wrong, but do we really disagree on anything here?

luisfontes commented 9 months ago

Sharing my use case for this feature. I'm in the process of building a Google Sheets add-on, and Google mandates that the HTML must be served from a single file with no local imports. Right now I'm using Svelte + Vite with vite-plugin-singlefile.

6eDesign commented 9 months ago

We use kit to build the frontend for a major tv manufacturer. Many of our SOCs have underwhelming performance and seem to struggle to efficiently download the 200+ JS files needed to load any given endpoint.

We use the static adapter currently as much of our content is very difficult to cache and SSR at this scale (tens of millions of active devices), without caching, becomes very "expensive" in many ways.

It would be great if we could experiment-with/optimize the build output for this use case (fewer files). If we could get help/advice with this (even in the form of some workaround/hack) I'd be more than happy to share some of the the real world results if it can help when deciding on the importance of this type of functionality in kit.

kewp commented 7 months ago

My use-case is like OP: I'm building both a full-page application, deployed on a separate server, and an embedded version that is inserted into Wordpress articles via shortcode. I have gotten this to work using Svelte but can't seem to figure out how to do it with Sveltekit.

kewp commented 7 months ago

@kauaicreative did you ever solve this? I have the exact same requirement as you ...

kewp commented 7 months ago

I've had some success (at least so far) using the shortcode adapter for my use case (for those with the same requirement) https://github.com/tomatrow/sveltekit-adapter-wordpress-shortcode

kewp commented 7 months ago

Yup got it working - just remember to turn off all load methods in your *.server.js files else you will get weird, un-debuggable JSON load errors coming from client.ts (trying to read JSON from a non-accessible server call). I know this isn't a support channel, just mentioning it for others!

GetCurious commented 7 months ago

My use case: Microsoft Dynamics 365

I want only 3 files: index.html index.js index.css

for now, using Svelte only

UnexDev commented 7 months ago

Use case: Microcontroller. (Pico W)

dsbaars commented 6 months ago

In my case I am using svelte to create a web interface inside an ESP32 (microcontroller), for the microcontroller, the fewer requests it has to attend to, the better, for this reason having everything in one file is ideal, or at least the html, js and css are each in a single file.

Similar use case here, also writing a web interface for a ESP32. As it uses SPIFFS/LittleFS, the filenames also need to be shorter than 31 characters.

AndrewPenry commented 5 months ago

My use case: The new PCI DSS 4.0 - 11.6.1 requires anyone with a payment page to monitor the page (as rendered by the client) weekly for changes, to make sure no one has modified the code. Writing synthetic user monitoring services (in Playwright or whatever) will be much easier if there are less files to compare. Note that the requirement as written prevents you from checking the integrity of your files just on the server side; it must monitor it on the client side to ensure it catches attacks injected by malicious 3rd parties.

craigkai commented 4 months ago

In my case I am using svelte to create a web interface inside an ESP32 (microcontroller), for the microcontroller, the fewer requests it has to attend to, the better, for this reason having everything in one file is ideal, or at least the html, js and css are each in a single file.

Similar use case here, also writing a web interface for a ESP32. As it uses SPIFFS/LittleFS, the filenames also need to be shorter than 31 characters.

Did you ever end up figuring this out?

dsbaars commented 4 months ago

Did you ever end up figuring this out?

I solved this in a quite ugly way. I created a patch that's applied automatically by patch-package when doing yarn install.

theelims commented 4 months ago

@craigkai My project contains a small plugin for vite to shorten the filenames: https://github.com/theelims/ESP32-sveltekit/blob/main/interface/vite-plugin-littlefs.ts which must then be included into https://github.com/theelims/ESP32-sveltekit/blob/main/interface/vite.config.ts

flo-at commented 4 months ago

Our use case: SPA that acts as the GUI to our software. SEO isn't a concern here at all. It works fine with many small files. But I'd prefer a longer initial loading time (for the bundles) and snappier navigation (fewer requests) over the current situation.

The websever serves precompressed files (br and gz) and large/merged files typically have a lot better compression ratio than small ones.

Ideally we could get this:

index.html
bundle.[hash].js
bundle.[hash].css
favicon.png
...

I'm overall pretty happy with Svelte(Kit). Thanks a lot for the awesome work!

katriellucas commented 3 months ago

Adding to the comment above: https://csswizardry.com/2023/10/the-three-c-concatenate-compress-cache/

This article explains how one file is sometimes better than a many files setup even in HTTP/2 scenarios, which is due to how compression works by comparing the file against itself. A big file has more "historical data" to use and ends up finding way more repetitions thus compressing better.

I think it makes sense to be able to controls this.

timoanttila commented 2 months ago

My use case for this would be admin area inside ProcessWire CMS. I want to import SvelteKit app with multiple pages to one PHP page. I have tried copying all the scripts and divs from the build folder's index.html and later tried using iframe. It would be perfect if there would be only one JS and CSS file. There is no need for SEO.

I want this to be fully client side because some of the information is dynamic and need to be fetched from backend after checking who user is and what rights (s)he has.

import adapter from '@sveltejs/adapter-static'
const vitePreprocess = import('@sveltejs/vite-plugin-svelte').then(m => m.vitePreprocess())

/** @type {import('@sveltejs/kit').Config} */
const config = {
  preprocess: {
    script: async options => (await vitePreprocess).script(options),
    style: async options => (await vitePreprocess).style(options)
  },
  kit: {
    adapter: adapter({
      fallback: 'index.html'
    }),
    prerender: {
      crawl: false,
      entries: []
    },
    alias: {src: './src'}
  }
}

export default config

I have used Vue before but I would really want to change to SvelteKit since it is much simpler and my frontend is made with it.

DougAnderson444 commented 2 months ago

I'd like to use SRI on the Svelte app code, so I need one file in order to hash it all and provide the integrity-hash on that one script.

gregg-cbs commented 1 month ago

Im not looking for a single file but im looking for less files. On my home page which does not have much i am seeing 75 js file requests. Some are 500bytes. I would like to be able to group components/imports/files into chunks so there arent all these bitty requests.

The issue I see is that my burger menu code is being loaded last and so the burger menu does not have any functionality until the whole page is completely loaded - on a slow network this is a horrible experience. If i could optimize this by grouping the burger menu code with other code/components into 1 file then my problem is alleviated.

Webpack has this functionality with their chunkName: import( /* webpackChunkName: "login" */ '../views/LoginView.vue'),

fortserious commented 1 month ago

Adding another use case for this feature.

In our company, our app is bundled into an WebView2 portal that's limited to displaying a single html file. We can inject file contents into this file, but we can't read these files from a subdirectory.

We are currently using Svelte + adapter-static + vite-plugin-singlefile to create a single index.html file and hand-rolling our own routing and that's working well for our purposes, but we'd ideally like to move to SvelteKit's native routing.

We can work with either a single .html file or a single .js, .css and .html file (as long as it could be expected that they all share the same root directory).