github remix-run/remix remix@3.1.0
remix v3.1.0

latest release: ui@0.13.0
3 hours ago

Minor Changes

  • Mixins created through remix/component can use createMixin(setup, { ssr: false }) to skip setup and render on the server while keeping browser behavior and hydration. Server rendering remains enabled by default. The option is intended for behavior that does not contribute to the server HTML. (#12019)

  • Server rendering with remix/component is about twice as fast as in 3.0 and uses less memory, with no code changes. Rendering a 48-product listing page with renderToString() takes 244 µs instead of 513 µs (Node.js 24.18 on an Apple M5 Pro, median of 5 fresh-process runs, identical HTML output). Under sustained HTTP load on a 24-product store page, assembling each response with a single join lowers the server's resident memory after load from 793 MiB to 527 MiB (see #12006, #12016, #12018, and #12020). (#12074)

    Apps that render client entries also benefit from getScriptEntry() caching in remix/assets: a warm lookup takes about 3 µs instead of 210 µs (see #12005). See the @remix-run/component and @remix-run/assets changelogs for details.

  • Use frame.reload({ src, method, encType, body }) from remix/component to reload another source or submit data and render the response without changing browser history. FormData follows GET query and POST encoding defaults, with multipart and plain-text encodings available. (#11938)

  • Prefetch frame HTML and assets with data-rmx-prefetch="intent", data-rmx-prefetch="viewport", or the imperative prefetch() API from remix/component. Both link modes support named frames and source overrides, respect Save-Data, and skip slow-2g/2g connections. See the prefetching guide for usage, customization, and caching behavior. (#12004)

  • Opt out of automatic focus resets during intercepted navigation with resetFocus: 'manual' in navigate() and link(), or data-rmx-reset-focus="manual" on links, forms, and submit buttons. Scroll and focus controls in remix/component now accept the Navigation API values "after-transition" (the default) and "manual"; existing boolean values remain supported. (#11939)

  • remix/file-storage/s3 now streams files to S3 with multipart uploads in storage.set(), so large files no longer need to fit in memory. A new partSize option controls the size of each part. See the @remix-run/file-storage-s3 changelog for details. (#12070)

  • Add remix/multipart-parser/future, remix/form-data-parser/future, and remix/middleware/form-data/future, which stream multipart parts and file uploads instead of buffering them in memory. Future APIs are not stable and may change in any release, but they are a good indication of where these packages will land in Remix's next major release. (#12030)

    In our benchmarks, parsing a request with a 100 MiB file upload takes 37 ms instead of 68 ms, the upload handler is called after 0.2 ms instead of 45 ms, and peak memory grows by 29 MiB instead of 396 MiB. Small forms perform the same as before. See the @remix-run/form-data-parser changelog for the full comparison.

    To try it in an app, import formData() from the /future entrypoint. Its options are the same as the stable middleware:

    -import { formData } from 'remix/middleware/form-data'
    +import { formData } from 'remix/middleware/form-data/future'
    
     export const router = createRouter({
       middleware: [
         formData({
           async uploadHandler(upload) {
             let key = crypto.randomUUID()
             await storage.set(key, upload)
             return key
           },
         }),
       ],
     })

    Each upload streams from the request body, so read it inside uploadHandler (for example by passing it to storage.set()). It can be read only once, upload.size is not available until it has been read, and upload.slice() is not supported. Uploads the handler returns unread are read into a regular File. Paired with the new streaming set() in remix/file-storage/s3, large uploads go straight to S3 without being held in memory.

    If your app handles file uploads, please give these entrypoints a try and tell us how it goes in GitHub Discussions. We'd especially like to hear about anything that breaks, behaves unexpectedly, or feels awkward, since that feedback will shape the next major release.

  • The remix/* entrypoints now preserve default exports from their underlying packages, including the callable assertion helper from remix/assert and SuperHeaders from remix/headers. (#12061)

    Added package.json exports:

    • remix/form-data-parser/future to re-export APIs from @remix-run/form-data-parser/future
    • remix/middleware/form-data/future to re-export APIs from @remix-run/form-data-middleware/future
    • remix/multipart-parser/future to re-export APIs from @remix-run/multipart-parser/future

Patch Changes

Don't miss a new remix release

NewReleases is sending notifications on new releases.