You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义SSR项目(非Next.js)中如何从服务器提供favicon.ico?

自定义SSR应用启动start脚本后favicon.ico 404问题

这是一个未使用Next.js的自定义SSR应用,devServer中运行正常,但执行start脚本启动服务器时,favicon.ico无法正常加载,出现404错误。

项目文件结构

├── assets
│   └── favicon.ico
├── client
│   ├── components
│   │   └── App.tsx
│   └── index.tsx
├── config
│   ├── tsconfig.client.json
│   ├── tsconfig.server.json
│   ├── webpack.client.config.ts
│   └── webpack.server.config.ts
├── dist
│   ├── client
│   │   ├── bundle.js
│   │   ├── favicon.ico
│   │   └── index.html
│   ├── server
│   │   ├── views
|   │   │   └── index.hbs
│   │   └── server.js
├── node_modules
├── server
│   ├── server.ts
│   └── views
│       └── index.hbs
├── types
│   └── custom.d.ts
├── .gitignore
├── package.json
└── tsconfig.json

静态资源托管配置

在server.ts中,通过Express托管dist/client目录作为静态资源:

app.use( express.static( path.resolve( __dirname, '../dist/client' ) ) )

Webpack服务器端配置

使用CopyWebpackPlugin复制favicon到dist/client,配置如下:

import path from 'path'
import webpack from 'webpack'
import nodeExternals from 'webpack-node-externals'
import CopyWebpackPlugin from 'copy-webpack-plugin'

const config: webpack.Configuration = {
    entry: './server/server.tsx',
    target: 'node',
    externals: [ nodeExternals() ],
    output: {
        path: path.resolve( __dirname, '../dist/server' ),
        filename: 'server.js'
    },
    mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
    resolve: {
        extensions: [ '.tsx', '.ts', '.js', '.jsx' ]
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new CopyWebpackPlugin( {
            patterns: [
                {
                    from: path.resolve( __dirname, '../server/views' ),
                    to: path.resolve( __dirname, '../dist/server/views' ),
                },
                {
                    from: path.resolve( __dirname, '../assets/favicon.ico' ),
                    to: path.resolve( __dirname, '../dist/client/' ),
                },
            ],
        } ),
    ],
    module: {
        rules: [
            {
                test: /\.(tsx?|js)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'ts-loader',
                    },
                ],
            },
        ]
    }
}

export default config

错误信息

浏览器控制台报错:

GET http://localhost:3000/favicon.ico 404 (Not Found)

错误截图

尝试将CopyWebpackPlugin移到客户端Webpack配置中时,会出现blob错误,情况异常。


解决方案

1. 确保构建流程完整

检查start脚本是否先执行了server端构建操作。如果直接运行dist/server/server.js但未重新构建,favicon可能没被复制到dist/client目录。修改package.json中的脚本,确保构建前置:

"scripts": {
  "build:server": "webpack --config config/webpack.server.config.ts",
  "build:client": "webpack --config config/webpack.client.config.ts",
  "build": "npm run build:client && npm run build:server",
  "start": "npm run build && node dist/server/server.js"
}

2. 修正Express静态资源路径

__dirname在编译后的server.js中指向dist/server,原路径写法本身正确,但可以换成更稳妥的绝对路径写法,避免工作目录差异导致的问题:

const rootDir = path.resolve(__dirname, '../../');
app.use(express.static(path.join(rootDir, 'dist/client')));

或简化为相对路径(Express会自动解析为当前进程工作目录的相对路径):

app.use(express.static('../dist/client'));

3. 修复客户端Webpack配置的blob错误

若将CopyWebpackPlugin移到客户端配置后出现blob错误,检查客户端Webpack的output.publicPath是否为'/',同时给CopyWebpackPlugin明确指定文件名:

new CopyWebpackPlugin({
  patterns: [
    {
      from: './assets/favicon.ico',
      to: './',
      filename: 'favicon.ico'
    }
  ]
})

确保客户端Webpack的output.path设置为dist/client,保证文件复制到正确目录。

4. 验证文件复制路径

启动服务前手动检查dist/client/favicon.ico是否存在。若不存在,调整CopyWebpackPlugin的路径写法,改用相对项目根目录的路径减少出错概率:

// 替换原from/to路径
{
  from: './assets/favicon.ico',
  to: '../dist/client/'
}

内容的提问来源于stack exchange,提问作者Brent Anderson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:24:56