webpack 项目访问静态资源

发布于:2024-11-29 ⋅ 阅读:(13) ⋅ 点赞:(0)

使用 webpack dev serve 启动 react 项目后,发现无法使用 http://localhost:8080/1.png 访问到项目的 /static 目录下的 1.png 文件。我的 webpack-dev.js 配置如下:

const webpack = require('webpack')
const webpackMerge = require('webpack-merge')
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const baseWebpackConfig = require('./webpack.config.base')
const proxy = require('../proxy/index.js')
const path = require('path')
const smp = new SpeedMeasurePlugin()

const config = webpackMerge.merge(baseWebpackConfig, {
  mode: 'development', // 模式 默认两种 production development
  devtool: 'cheap-module-eval-source-map',
  plugins: [
    new webpack.HotModuleReplacementPlugin() // 热更新插件
  ],
  devServer: { // 开发服务器配置
    hot: true,
    port: 8080,
    open: false,
    quiet: false,
    inline: true,
    stats: 'errors-only',
    overlay: false,
    clientLogLevel: 'silent',
    compress: true,
    // contentBase: path.join(__dirname, 'dist'),
    contentBase: path.join(__dirname, '../static'), // 设置开发服务器根目录
    proxy: {
      '/': {
        bypass: function (req, res, proxyOptions) {
          return `/index.html`
        }
      },
      ...proxy
    }
  }
})

module.exports = config

发现是 proxy 的配置下 把 访问 / 的路径全部拦截到 /index.html 下了,所以访问不到 /static 目录下的静态资源。

解决方案
改一下 proxy 的逻辑即可,修改后的 webpack-dev.js 配置:

const webpack = require('webpack')
const webpackMerge = require('webpack-merge')
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const baseWebpackConfig = require('./webpack.config.base')
const proxy = require('../proxy/index.js')
const path = require('path')
const smp = new SpeedMeasurePlugin()

const config = webpackMerge.merge(baseWebpackConfig, {
  mode: 'development', // 模式 默认两种 production development
  devtool: 'cheap-module-eval-source-map',
  plugins: [
    new webpack.HotModuleReplacementPlugin() // 热更新插件
  ],
  devServer: { // 开发服务器配置
    hot: true,
    port: 8080,
    open: false,
    quiet: false,
    inline: true,
    stats: 'errors-only',
    overlay: false,
    clientLogLevel: 'silent',
    compress: true,
    // contentBase: path.join(__dirname, 'dist'),
    contentBase: path.join(__dirname, '../static'), // 设置开发服务器根目录
    proxy: {
      '/': {
        bypass: function (req, res, proxyOptions) {
          // 如果请求的是以 /static/resources 开头的路径,不做重定向,直接返回 null
          if (req.url.startsWith('/resources')) {
            return null;  // 不重定向,继续处理静态资源
          }
          return `/index.html`
        }
      },
      ...proxy
    }
  }
})

module.exports = config

相关文档可以参考 webpack 官网 - proxy


继续展开

我发现我执行 npm run build 无法将 我的react项目跟目录下的 /static/resources/pdf/ 资源打包到 dist 目录中。

解决办法:

安装 copy-webpack-plugin@6.0.0 插件, 这个版本适配 webpack@4.41.5 这个版本,已经测试可用。

npm install copy-webpack-plugin@6.0.0

然后再 webpack.base.js 配置:

const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
    new CopyWebpackPlugin({
      patterns: [
        { from: 'static/resources/pdf', to: 'static/resources/pdf' }
      ]
    })
  ]
}

手动指定要复制的资源,这样执行 npm run build 之后就能将 /static/resources/pdf下的文件打包到 /dist/static/resources/pdf 目录下了。


继续展开

我有一个需求就是要将文档放在项目目录中,然后用户点击下载按钮,就找到项目中的对应文件下载。
代码如下:


  function createAndRemove(url, fileName) {
  	// 创建 a 标签
    var link= document.createElement('a');
    // 下载内容转变成blob地址
    link.href = process.env.INTERFACE_DOCUMENT + "a.pdf";
    link.download = fileName;
    // 触发点击
    document.body.appendChild(link);
    eleLink.click();
    // 然后移除
    document.body.removeChild(link);
  }

为什么要用 process.env.INTERFACE_DOCUMENT 这个变量?

因为项目部署在本地(通过 npm start 启动) 和 部署到线上路径可能会不一样。

a.pdf 文件在项目的根目录下的 /static/resources/pdf/ , 访问路径为 http://localhost:8080/resources/pdf/a.pdf

项目打包后, a.pdf 会被打包到 /dist/static/resources/pdf/ , 部署到线上后,使用的 nginx 部署项目, nginx 的配置指定 dist 为根目录,

nginx.conf 配置如下

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    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;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        #root         /usr/share/nginx/html;
	root 	     /project;

	location / {
		root /dist;
		index	 index.html index.htm;
		try_files	 $uri $uri/ /index.html;  # 解决页面路由问题,刷新页面返回 404
	}

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}


dist 目录结构为

|- dist
|-----static
|---------- img
|---------- css
|---------- js
|---------- resources
|-----------------pdf 

在这里插入图片描述
此时线上访问 a.pdf 的路径为 http://ip:port/static/resources/pdf/a.pdf

所以才会有根据环境变量来获取 URL的这段代码 process.env.INTERFACE_DOCUMENT。

.env.development 文件

INTERFACE_DOCUMENT=/resources/pdf/

.env.production 文件

INTERFACE_DOCUMENT=/static/resources/pdf/

这样配置完后,在本地和在线上就都能够正常下载了。

注意:如果你的文件名为中文,部署到 linux 中,中文可能会乱码,会导致找不到文件,所以最好使用英文文件名。