阅读 884

Webpack打包css中引用font、img等资源文件的路径问题

问题探究

Css中引入的各种资源,在开发环境下可以正常获取,但是打包之后在生产环境经常会出现资源路径错误的问题

分析

这个问题一般都是生产环境下的资源路径配置不正确导致的,包括css、font、img等资源文件的配置

Css配置

注意:MiniCssExtractPlugin一般在生产环境下才会使用,开发环境下一般用style-loader,它包含plugin和loader两部分,需要一起使用

plugin

MiniCssExtractPlugin

压缩css并把压缩后文件移动到指定位置

new MiniCssExtractPlugin({
    filename: 'assets/css/[name].css',
    chunkFileName: 'assets/css/[name].css'
})
复制代码

loader

MiniCssExtractPlugin.loader

其中路径相关比较重要的参数是publicPath,它表示css会从哪里开始寻找资源。

举个🌰:

源码文件夹结构:

image.png

test.css中引入图片

// test.css
@font-face {
  font-family: fa;
  src: url("./assets/somefont.woff");
}

.main {
    background: url("./images/somepic.png");
}
复制代码

Css中使用url引入图片和font文件时使用的路径是相对于css的相对路径,生产环境使用MiniCssExtractPlugin将css从js文件中分离出来,打包后的文件在assets/css下,css中的文件引用如果使用相对路径,那么打包后路径会出现错误

一、 先添加css路径和publicPath的配置:

// plugin的配置
new MiniCssExtractPlugin({
    filename: 'assets/css/[name].css',
    chunkFileName: 'assets/css/[name].css'
})

// loader的配置
{
    loader: MiniCssExtractPlugin.loader,
    publicPath: '../../'   // 因为filename配置了两层文件夹,publicPath中要向上查找两次来找到项目根路径
}

复制代码

二、配置资源路径:

// 图片配置
{
    test: /\.(png|jpg|bmp|gif)$/i,
    type: "asset/resource",
    generator: {
         fliename: "static/[name].[ext]" // 打包后的图片会被移动到 dist/static文件夹下
    }
}

// font配置
{
    test: /\.(woff|woff2|eot|otf)$/i,
    type: "asset/resource",
    generator: {
         filename: "assets/font/[name].[ext]" // 打包后的字体文件会被移动到dist/asset/font文件夹下
    }
},
复制代码

打包后的文件路径如下:

image.png

css中的url如果按之前的引用肯定会找不到资源

webpack会根据publicPath和资源路径来拼接一个路径: path.join([publicPath], [资源路径])来替换url()中的路径,而资源路径也应用了webpack配置

  • publicPath: ../../

  • 配置的资源路径为:

    • 图片:static/[name].[ext]
    • font:assets/fonts/[name].[ext]

可以这么理解: 打包时先把所有的css、font、img资源文件,按照配置复制到dist文件夹下,然后修改css文件中的url(),保证可以找到资源。

// 所以最后test.css中的url会被替换成这样
@font-face {
  font-family: fa;
  // 1. 前缀: "../../"
  // 2. .woff文件打包后的位置: "assets/fonts/somefont.woff"
  // 3. 最终路径 = 前缀 + .woff文件打包后的位置
  //             👇👇👇
  // "../../assets/fonts/somefont.woff"
  src: url("../../assets/fonts/somefont.woff");
}

.main {
    background: url("../../static/somepic.png");
}
复制代码

再贴一下最终目录,可以观察一下css文件的和font、img的相对位置,会发现按照我们的配置,可以成功获取到资源,不会有任何问题。

image.png

大功告成!!

总结

打包后css中的url()资源路径跟源代码里写的路径没有任何关系,只跟配置有关,打包时webpack会按照我们的配置把资源文件复制到指定的位置,然后把css源码中url()中的路径替换成我们配置的路径

完整的配置文件如下:

// webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
exports.module = {
    // ...
    output: 'dist',
    plugins: [
        // ... 配置css文件的打包路径
        new MiniCssExtractPlugin({
                filename: 'assets/css/[name].[contenthash:8].css',
                chunkFileName: 'assets/css/[name].[contenthash:8].css'
        })
    ],
    module: {
        rules: [
            {
                test: /\.(woff|woff2|eot|otf)$/i,
                type: "asset/resource",
                generator: {
                        filename: "assets/fonts/[name].[contenthash:8].[ext]"
                }
            },
            {
                test: /\.(png|jpg|bmp|gif)$/i,
                type: "asset/resource",
                generator: {
                        fliename: "static/[name].[contenthash:8].[ext]"
                }
            },
            {
                test: /.css$/,
                use: [
                {
                    loader: MiniCssExtractPlugin.loader,
                    options: {
                        esModule: false,   // 使用commonjs规范解析css,require引入可以不加.default
                        publicPath: '../../' // 使url的查找路径为dist根路径
                    }
                }, 
                "css-loader"
                ]
            }
        ],
    }
}
复制代码
文章分类
前端
文章标签