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

feat: modern server static should always use system fs #6924

Merged
merged 2 commits into from
Mar 11, 2025

Conversation

zllkjc
Copy link
Member

@zllkjc zllkjc commented Mar 11, 2025

Summary

Currently, there is inconsistency between the behavior in development and production environments. There are two middleware for hosting static resources:

  1. Rsbuild devMiddleware, hosts bundler assets, the assets not process by bundler will not be hosted.
  2. Modern.js staticMiddleware, hosts resources in static/, upload/, and other specific directories. And this middleware will use bundler's outputFileSystem instead real file system in dev mode.

In development, the request process by these two middlewares. But in production, only process by Modern.js staticMiddleware.

This design will lead to many strange issues:

  1. The dist/a.json file, process by bundler. It can be accessed in development, but can't be accessed in production.

  2. The dist/static/a.json file, not process by bundler. It can't be accessed in development, but can be accessed in production.

  3. The Modern.js staticMiddleware do nothing in development, becasue it always use bundler's outputFileSystem, so the file can't be find in rsbuild devMiddleware also can't be find in Modern.js staticMiddleware.

Therefore, we need to clarify this part of the logic and explain why we are doing it this way.

First, Modern.js staticMiddleware should only host resources from specified directories, and we should not expose server code to the outside.

Based on this, we need to ensure that user behavior remains as consistent as possible between the development and production stages.

Because during the development, rsbuild devMiddleware always hosts all bundlers, but Modern.js staticMiddleware cannot determine which files need to be hosted in the production environment (perhaps we could record bundler outputs, but this is not secure). However, due to security principles, Modern.js staticMiddleware cannot host the entire output directory.

Therefore, we ultimately considered this approach:

  1. During the development phase, both middleware work, but staticMiddleware no longer uses the bundler's outputFileSystem, instead using the system's fileSystem. This ensures that files in the static/ directory that are not generated by the bundler behave consistently between development and production environments.

  2. The file not in static/ or upload/ dir should never be hold by statciMiddleware. For example, jsPath, cssPath, favicon.ico, etc.. But due to historical reasons, we have retained them in this major version.

  3. Files generated by the bundler during the development that can be accessed through rsbuild devMiddleware but are not in the static/ directory will still be inaccessible through staticMiddleware in the production environment. We expect users to handle these files themselves, such as moving them to deployment artifacts as needed when deploying to Netlify, or uploading them to a CDN at some stage.

The above is the discussion regarding static resource handling. Next.js has similar behavior, but it might be even stricter.

In this PR, we have replaced the fileSystem of staticMiddleware with the system's fileSystem. In the following PRs, we will gradually implement the changes according to the behavior described above.

  • Support dev.assetPrefix for staticMiddleware.
  • Support phase which developer can move some dist file to deploy production directory.
  • Remove some historical logic in staticMiddleware.

由于内容比较多,提供中文版

目前,开发环境和生产环境的行为存在不一致。有两个用于托管静态资源的中间件:

  1. Rsbuild devMiddleware,托管由 bundler 处理的资源,未经 bundler 处理的资源不会被托管。
  2. Modern.js staticMiddleware,托管 static/upload/ 和其他特定目录中的资源。在开发模式下,该中间件会使用 bundler 的 outputFileSystem 而不是真实的文件系统。

在开发环境中,请求会经过这两个中间件处理。但在生产环境中,只会经过 Modern.js staticMiddleware 处理。

这种设计会导致许多奇怪的问题:

  1. dist/a.json 文件,由 bundler 处理。在开发环境中可以访问,但在生产环境中无法访问。
  2. dist/static/a.json 文件,未经 bundler 处理。在开发环境中无法访问,但在生产环境中可以访问。
  3. Modern.js staticMiddleware 在开发环境中实际上没有作用,因为它总是使用 bundler 的 outputFileSystem,因此在 rsbuild devMiddleware 中找不到的文件,在 Modern.js staticMiddleware 中也找不到。

因此,我们需要明确这部分逻辑,并解释为什么这样做。

首先,Modern.js staticMiddleware 应该只托管指定目录中的资源,我们不应该将服务器代码暴露给外部。

基于这一点,我们需要确保用户行为在开发和生产阶段尽可能保持一致。

在开发过程中,rsbuild devMiddleware 总是托管所有 bundler 处理的资源,但 Modern.js staticMiddleware 无法确定生产环境中需要托管哪些文件非 static/ 目录下的文件(也许我们可以记录 bundler 的输出,但这并不安全)。而因为安全性原则,Modenr.js staticMiddleware 又不能托管整个产物目录。

因此,我们最终考虑了以下方法:

  1. 在开发阶段,两个中间件同时工作,但 staticMiddleware 不再使用 bundler 的 outputFileSystem,而是使用系统的 fileSystem。这确保了 static/ 目录下并且不是由 bundler 生成的文件在开发和生产环境中的行为一致。
  2. 不在 static/upload/ 目录下的文件永远不应该由 staticMiddleware 托管。例如 jsPathcssPath favicon.ico 等。但由于历史原因,我们在这个大版本中保留了它们。
  3. 由 bundler 生成,但不在 static/ 目录下的文件,在开发阶段可以通过 rsbuild devMiddleware 访问,但在生产环境中仍然无法通过 staticMiddleware 访问。我们期望用户自己处理这些文件,例如在部署到 Netlify 时按需将文件移动到部署产物中,或在某个阶段将它们上传到 CDN。

以上就是关于静态资源处理的讨论。Next.js 有类似的行为,但可能更加严格。

在这个 PR 中,我们已经将 staticMiddleware 的 fileSystem 替换为系统的 fileSystem。在接下来的 PR 中,我们将逐步按照上述行为进行改动。

  • staticMiddleware 在开发阶段应该支持 dev.assetPrefix 配置。
  • 支持开发者在某些阶段,可以将某些 dist 文件移动到生产部署目录。
  • 在下一个大版本中,移除 staticMiddleware 中的一些历史逻辑

Related Links

Checklist

  • I have added changeset via pnpm run change.
  • I have updated the documentation.
  • I have added tests to cover my changes.

Copy link

changeset-bot bot commented Mar 11, 2025

🦋 Changeset detected

Latest commit: dd0c0c0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 286 packages
Name Type
@modern-js/runtime-utils Patch
@modern-js/server-core Patch
@modern-js/plugin-data-loader Patch
@modern-js/plugin-tailwindcss Patch
@modern-js/plugin-garfish Patch
@modern-js/plugin-router-v5 Patch
@modern-js/runtime Patch
@modern-js/create-request Patch
@modern-js/plugin-server Patch
@modern-js/prod-server Patch
@modern-js/server Patch
@modern-js/plugin-v2 Patch
app-entry-server Patch
@modern-js/plugin-bff Patch
@modern-js/plugin-devtools Patch
@modern-js/plugin-testing Patch
@modern-js/render Patch
@modern-js/plugin-express Patch
@modern-js/plugin-koa Patch
@modern-js/plugin-polyfill Patch
@modern-js/server-utils Patch
@modern-js/app-tools Patch
server-config-v2 Patch
server-config Patch
integration-tailwindcss-v2 Patch
integration-tailwindcss-v3-js-config Patch
integration-tailwindcss-v3-merge-config Patch
integration-tailwindcss-v3-ts-config Patch
integration-tailwindcss-v3 Patch
twin-macro-v2 Patch
twin-macro-v3 Patch
app-garfish-dashboard Patch
app-garfish-master Patch
app-garfish-table Patch
@e2e/garfish-dashboard-router-v6 Patch
@e2e/garfish-dashboard Patch
@e2e/garfish-main-router-v6 Patch
@e2e/garfish-main Patch
@e2e/garfish-table Patch
app-document Patch
file-based-router Patch
@modern-js/devtools-client Patch
@modern-js/storybook-builder Patch
@integration-test/alias-set Patch
api-service-koa Patch
async-entry-test Patch
tmp Patch
bff-api-app Patch
bff-client-app Patch
bff-indep-client-app Patch
bff-express Patch
bff-koa Patch
integration-clean-dist-path Patch
integration-compatibility Patch
integration-custom-dist-path Patch
custom-file-system-entry Patch
integration-custom-render Patch
integration-custom-template Patch
deploy Patch
deploy-server Patch
dev-server Patch
@integration-test/devtools Patch
integration-disable-html Patch
app-custom-bootstrap Patch
app-custom-routes-runtime Patch
app-custom Patch
app-entry Patch
app-route Patch
esbuild-transform-and-minify Patch
main-entry-name Patch
nonce Patch
pure-esm-project Patch
routes-match Patch
routes Patch
app-rsbuild-hooks Patch
rsc-csr-app Patch
rsc-ssr-app Patch
runtime-custom-plugin Patch
runtime-custom-config-plugin Patch
use-loader Patch
select-mul-entry-test Patch
select-one-entry-test Patch
server-middleware Patch
server-new-middleware Patch
server-hook-reqeust Patch
server-hook-response Patch
server-hook-router Patch
@integration-test/server-hook-reqeust Patch
server-json-script Patch
server-monitors Patch
server-prod Patch
server-routes Patch
@source-code-build/app-ts-loader Patch
@source-code-build/app Patch
ssg-fixtures-mega-list-routes Patch
ssg-fixtures-nested-routes Patch
ssg-fixtures-simple Patch
ssg-fixtures-web-server Patch
ssr-base-async-entry-test Patch
ssr-base-json-test Patch
ssr-base-test Patch
ssr-base-fallback-test Patch
init Patch
ssr-inline Patch
ssr-partial-test Patch
ssr-script-loading Patch
ssr-streaming-inline-test Patch
ssr-streaming-test Patch
swc-config-function Patch
swc-minify-css Patch
swc-minify-js Patch
transform-fail Patch
tmp-dir Patch
transform-import-type-test Patch
transform-import-type-lodash Patch
write-to-dist Patch
@modern-js/plugin-ssg Patch
@modern-js/plugin-worker Patch
@modern-js/plugin-swc Patch
@modern-js/devtools-kit Patch
tests Patch
integration-asset-prefix Patch
integration-builder-plugins Patch
integration-copy-assets Patch
entries-app-builder-index Patch
entries-app-builder Patch
integration-config-async-config-test Patch
integration-basic-local-config Patch
integration-config-function-params Patch
integration-local-config-function Patch
swc-test-decorator-legacy Patch
swc-test-decorator Patch
@modern-js/storybook Patch
integration-tests-storybook Patch
@modern-js/tsconfig Patch
@modern-js/babel-preset Patch
@modern-js/core Patch
@modern-js/flight-server-transform-plugin Patch
@modern-js/plugin-changeset Patch
@modern-js/plugin-i18n Patch
@modern-js/plugin-proxy Patch
@modern-js/rsbuild-plugin-esbuild Patch
@modern-js/uni-builder Patch
@modern-js/main-doc Patch
@modern-js/module-tools-docs Patch
@modern-js/new-action Patch
@modern-js/sandpack-react Patch
@modern-js/babel-plugin-module-resolver Patch
@modern-js/bff-core Patch
@modern-js/bff-runtime Patch
@modern-js/plugin-module-babel Patch
@modern-js/plugin-module-banner Patch
@modern-js/plugin-module-import Patch
@modern-js/plugin-module-node-polyfill Patch
@modern-js/plugin-module-polyfill Patch
@modern-js/plugin-module-vue Patch
@modern-js/module-tools Patch
@modern-js/monorepo-tools Patch
@modern-js/create Patch
@modern-js/e2e Patch
@modern-js/node-bundle-require Patch
@modern-js/plugin Patch
@modern-js/types Patch
@modern-js/upgrade Patch
@modern-js/utils Patch
@modern-js/babel-compiler Patch
@scripts/build Patch
@scripts/check-changeset Patch
@scripts/jest-config Patch
@scripts/lint-package-json Patch
@scripts/prebundle Patch
@scripts/release-versin Patch
@scripts/update-codesmith Patch
@scripts/vitest-config Patch
entries-integration Patch
esbuild-integration Patch
integration-load-config Patch
alias-js-test Patch
alias-module-id-test Patch
alias-ts-test Patch
asset-limit-test Patch
asset-name-test Patch
asset-path-test Patch
asset-publicPath-test Patch
svgr-test Patch
auto-extension-commonjs-test Patch
auto-extension-type-module-test Patch
auto-external-test Patch
banner-footer-test Patch
build-type-test Patch
copy-test Patch
decorator-test Patch
global-vars-js-test Patch
global-vars-ts-test Patch
dts-composite Patch
dts-test Patch
esbuild-options-test Patch
external-test Patch
format-cjs-test Patch
format-esm-test Patch
format-iife-test Patch
format-umd-test Patch
hook-test Patch
entry-test Patch
jsx-test Patch
loader-esbuild-test Patch
loader-swc-test Patch
metafile-test Patch
minify-test Patch
platform-test Patch
redirect-test Patch
resolve-alias-error Patch
resolve-alias-test Patch
data-url-test Patch
browser-false Patch
resolve-false Patch
ndoe-protocol-test Patch
lib1 Patch
lib2 Patch
lib3 Patch
condition-exports-test Patch
js-extensions-test Patch
main-fields-test Patch
shims-test Patch
module-tools-side-effects-test Patch
source-dir-test Patch
sourcemap-test Patch
splitting-test Patch
css-test Patch
less-test Patch
style-test Patch
postcss-test Patch
sass-test Patch
scss-test Patch
tailwindcss-test Patch
target-test Patch
transform-import Patch
transform-lodash Patch
tsconfig-test Patch
tsconfig-extends-test Patch
umdGlobals-test Patch
get-module-id-test Patch
dev-test Patch
build-platform-test Patch
build-preset-error-test Patch
build-preset-function-test Patch
build-preset-test Patch
build-preset-string-test Patch
integration-module-tools Patch
plugin-babel Patch
module-hooks-test Patch
plugin-node-polyfill Patch
plugin-polyfill Patch
plugin-vue Patch
runtime Patch
entry Patch
@source-code-build/common Patch
@source-code-build/components Patch
@source-code-build/utils Patch
ssg Patch
ssr Patch
swc-integration Patch
tailwindcss-integration-test Patch
@e2e/webpack-builder-import-antd-v4 Patch
@e2e/webpack-builder-import-antd-v5 Patch
@e2e/webpack-builder-import-arco Patch
@e2e/webpack-builder-test-moment Patch
@e2e/builder-remove-prop-types Patch
@e2e/webpack-builder-source-map Patch
@e2e/builder Patch
@e2e/garfish Patch
@modern-js/generator-common Patch
@modern-js/generator-utils Patch
@modern-js/bff-generator Patch
@modern-js/dependence-generator Patch
@modern-js/entry-generator Patch
@modern-js/mwa-generator Patch
@modern-js/router-v5-generator Patch
@modern-js/ssg-generator Patch
@modern-js/storybook-next-generator Patch
@modern-js/upgrade-generator Patch
@modern-js/generator-cases Patch
@modern-js/base-generator Patch
@modern-js/packages-generator Patch
@modern-js/server-generator Patch
@modern-js/tailwindcss-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

netlify bot commented Mar 11, 2025

Deploy Preview for modernjs-byted ready!

Name Link
🔨 Latest commit dd0c0c0
🔍 Latest deploy log https://app.netlify.com/sites/modernjs-byted/deploys/67cfccf9e0b3330008e84c08
😎 Deploy Preview https://deploy-preview-6924--modernjs-byted.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 48 (🔴 down 7 from production)
Accessibility: 90 (no change from production)
Best Practices: 100 (no change from production)
SEO: 91 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

@zllkjc zllkjc merged commit f1cd095 into main Mar 11, 2025
11 checks passed
@zllkjc zllkjc deleted the feat/serve-static-fs branch March 11, 2025 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants