LitElement应用部署Nginx后加载失败,MIME类型错误求助
问题
将LitElement静态网页应用部署至Nginx服务器后,在Google Chrome中打开时页面持续加载但无内容,浏览器控制台出现两个错误:
- Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
- workflow/:1 ServiceWorker registration failed: DOMException: Failed to register a ServiceWorker for scope ('https://frontend.net/') with script ('https://frontend.net/sw.js'): The script has an unsupported MIME type ('text/html').
该应用在本地通过Node.js的serve工具运行完全正常,相关配置文件如下:
nginx.conf
worker_processes auto; error_log /var/log/nginx/error.log notice; pid /tmp/nginx.pid; events { worker_connections 1024; } http { proxy_temp_path /tmp/proxy_temp; client_body_temp_path /tmp/client_temp; fastcgi_temp_path /tmp/fastcgi_temp; uwsgi_temp_path /tmp/uwsgi_temp; scgi_temp_path /tmp/scgi_temp; include /etc/nginx/mime.types; types { application/javascript js mjs; } default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; server { listen 8080; root /usr/share/nginx/html; index index.html index.htm; server_name localhost; server_tokens off; location / { try_files $uri $uri/ /index.html; } error_page 404 405 406 500 502 503 504 /error_frontend.html; location = /error_aria.html { root /usr/share/nginx/html; } } }
rollup.config.js
import nodeResolve from '@rollup/plugin-node-resolve'; import babel from '@rollup/plugin-babel'; import html from '@web/rollup-plugin-html'; import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets'; import esbuild from 'rollup-plugin-esbuild'; import { generateSW } from 'rollup-plugin-workbox'; import path from 'path'; export default { input: path.join(__dirname, './index.html'), output: { entryFileNames: '[hash].js', chunkFileNames: '[hash].js', assetFileNames: '[hash][extname]', format: 'es', dir: 'dist', }, preserveEntrySignatures: false, plugins: [ /** Enable using HTML as rollup entrypoint */ html({ minify: true, injectServiceWorker: true, serviceWorkerPath: 'dist/sw.js', }), /** Resolve bare module imports */ nodeResolve(), /** Minify JS, compile JS to a lower language target */ esbuild({ minify: true, target: ['chrome64', 'firefox67', 'safari11.1'], }), /** Bundle assets references via import.meta.url */ importMetaAssets(), /** Minify html and css tagged template literals */ babel({ plugins: [ [ require.resolve('babel-plugin-template-html-minifier'), { modules: { lit: ['html', { name: 'css', encapsulation: 'style' }] }, failOnError: false, strictCSS: true, htmlMinifier: { collapseWhitespace: true, conservativeCollapse: true, removeComments: true, caseSensitive: true, minifyCSS: true, }, }, ], ], }), /** Create and inject a service worker */ generateSW({ globIgnores: ['polyfills/*.js', 'nomodule-*.js'], navigateFallback: './index.html', // where to output the generated sw swDest: path.join('dist', 'sw.js'), // directory to match patterns against to be precached globDirectory: path.join('dist'), // cache any html js and css by default globPatterns: ['**/*.{html,js,css,webmanifest}'], skipWaiting: true, clientsClaim: true, runtimeCaching: [{ urlPattern: 'polyfills/*.js', handler: 'CacheFirst' }], }), ], context: "window" };
index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" /> <meta name="Description" content="Put your description here."> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /> <base href="/"> <style> html, body { margin: 0; padding: 0; font-family: sans-serif; background-color: #ededed; } </style> <title>frontend</title> <script> window.process = { env: { NODE_ENV: 'production', REDIRECTION_URL: 'https://frontend.net/', } }; </script> </head> <body> <frontend></frontend> <script type="module" src="./out-tsc/src/frontend.js"></script> </body> </html>
解决方案
两个错误的核心原因是Nginx返回了错误的MIME类型:请求JS模块文件和Service Worker文件时,Nginx未找到对应文件,转而返回index.html,导致浏览器接收到text/html类型响应,但预期是application/javascript。
具体原因
- 部署文件不匹配:本地开发的文件结构与Nginx部署路径不一致。Rollup编译产物输出到
dist目录,但部署时可能未将dist下的所有文件复制到Nginx的root目录(/usr/share/nginx/html),而是直接复制了源码文件。 - Nginx规则导致的 fallback:
try_files $uri $uri/ /index.html规则会在文件不存在时直接返回index.html,浏览器将HTML当作JS模块解析,触发MIME类型错误。
修复步骤
步骤1:部署Rollup编译后的完整产物
执行rollup -c完成编译后,将dist目录下的所有文件复制到Nginx的root目录(/usr/share/nginx/html),不要直接复制源码目录的文件。
步骤2:使用Rollup生成的index.html
@web/rollup-plugin-html插件会自动处理JS模块的引用路径,编译后的dist/index.html已包含正确的哈希文件名引用,直接使用该文件即可,不要手动修改。
步骤3:优化Nginx配置(可选)
调整配置,确保静态资源返回正确的MIME类型,同时区分路由请求和静态资源请求:
http { include /etc/nginx/mime.types; types { application/javascript js mjs; text/javascript js; } default_type application/octet-stream; server { listen 8080; root /usr/share/nginx/html; index index.html index.htm; server_name localhost; server_tokens off; location / { try_files $uri $uri/ @fallback; } # 仅路由请求返回index.html,静态资源不存在则返回404 location @fallback { rewrite ^ /index.html last; } # 静态资源缓存配置 location ~* \.(js|css|html|png|jpg|webmanifest)$ { expires 1y; add_header Cache-Control "public, immutable"; } error_page 404 405 406 500 502 503 504 /error_frontend.html; location = /error_frontend.html { root /usr/share/nginx/html; } } }
步骤4:验证Service Worker路径
确保dist/sw.js存在,Rollup的generateSW插件会自动注入正确的Service Worker路径,只要dist目录完整部署即可。
内容的提问来源于stack exchange,提问作者Piotr Treska
相关产品推荐
相关产品推荐

