PostCss、Webpack中的file-loader、url-loader、asset module type

365 阅读4分钟

引言:浏览器的兼容性,我们这里的兼容性是指对CSS、JS的兼容性,但是现在前端已经非常工程化,比如css可以用autoprefixer来给浏览器加前缀,就不用我们手动添加,但是这也会导致一个问题,我可能只需要给适配部分浏览器加前缀,那使用autoprefixer可能给的是适配所有浏览器加前缀,这无疑导致了代码量的增多,因此要不要用autoprefixer给css加前缀是不一定的,这取决于我们到底要适配哪些浏览器。

我们在很多的脚手架配置中,比如vue中的.browserslistrc文件,react中package.json里面的browserslist,都能看到类似于这样的信息:

>1%
last 2 versions
not dead

这是条件都是提供给工具告诉这些工具我现在到底要适配哪些浏览器,比如>1%,是说浏览器的市场占有率要大于1%,那么关于浏览器的市场占有率在哪看呢?答案是在can i use网站。

还有个问题我们如何可以在css兼容性和js兼容性下共享我们配置的兼容性条件呢?比如我们设置了>1%的条件,不仅要css兼容市场占有率大于1%的浏览器,js也要,如果我们是通过工具来达到这种兼容性的,比如babel、autoprefixer,我们如何让他们共享我们的配置呢,答案是Browserlist,Browserlist是一个在不同的前端工具之间,共享目标浏览器和Node.js版本的配置

我们编写了这么多条件,这些条件之间是什么关系呢?条件以逗号分隔的话是并集关系,以空格分割的话是交集关系

在哪里编写?一种是可以在packge.json的devDependencies的同级下,写一个browserslist数组,比如"browserslist":[">1%","last 2 versions"],到时候bable和autoprefixer就会自动查找到browserslist;另一种是建一个.browserslistrc文件,在里面写条件,条件不用加引号

那么之后这些工具会根据我们的配置来获取相关的浏览器信息,如何获取呢?用的是caniuse-lite的工具,这个工具的数据来自于caniuse的网站上

PostCss

postcss是一个通过JavaScript来转换样式的工具,这个工具可以帮助我们进行一些css的转换和适配,比如自动添加浏览器前缀,但是实现这些功能,我们需要借助于PostCss对应的插件;

如何使用?1、查找PostCss在构建工具中的扩展,比如webpack中的postcss-loader 2、选择可以添加你需要的PostCss相关的插件

npm install postcss-loader -D 在配置postcss-loader时,我们配置插件使用postcss-preset-env,他可以将一些现代的css特性,转成大多数浏览器认识的css,并且会根据目标器或者运行时环境添加所需的polyfill,也包括会自动帮助我们添加autoprefixer,相当于内置了autoprefixer

npm install postcss-preset-env -D

const path =require('path')
module.exports={
    entry:'./main.js',
    output:{'bundle.js',
    path:path.resolve(__dirname,'./build)'
    },
    module:{
        rules:[
            {
            test:/\.css$/,
            use:[
            "style-loader",
            "css-loader",
            {loader:"postcss-loader",
            options:{
                postcssOptions:{
                plugins:["postcss-preset-env"]
                    }
                }
               }
              ]
            }
           ]
        }
}

file-loader

要处理jpg、png等格式的图片,我们也需要有对应的loader:file-loader(记得使用之前要安装), file-loader的作用就是帮我们处理引入的文件资源,并且会将他们放到我们输出的文件夹中,相当于是把打包的文件资源复制到打包后的文件夹中,打包之后的文件的名字是一长串哈希值,我们想要改变打包之后的文件的名字的话可以这样:

图片.png

于是我们webpack配置中可以这样写:

const path =require('path')
module.exports={
    entry:'./main.js',
    output:{'bundle.js',
    path:path.resolve(__dirname,'./build)'
    },
    module:{
        rules:[
            {
            test:/\.(png|jpeg|jpg|gif|svg)$/,
            use:[
            {
                loader:"file-loader",
                options:{
                    name:"[name].[hash:6].[ext]"
                    //ext表示以原文件的格式为打包格式,比如原文件是png,那么打包之后还是png,[name].[hash:6]是打包后的文件名,以原文件的文件名+6位hash值为打包后的文件的名字
                
                }
            }
                ]
            }
          ]
        }
}

如果我们想要把这些匹配到的文件打包后放在同一个文件夹下,可以把options中的name这样写: options:{ name:"img/[name].[hash:6].[ext]" } 表示把匹配到的文件都打包到img文件夹下

url-loader

url-loader和file-loader的工作方式是一样的,但是可以将较小的文件,转成base64的URI,这是因为如果所有图片都转换成base64就会导致打包出来的js文件非常大,那网页加载打包出来的js文件的时候需要较长时间才能把js文件下载下来,所以比较小的图片转换成base64直接嵌入到打包出来的js文件中,大的图片单独发送http请求,

const path =require('path')
module.exports={
    entry:'./main.js',
    output:{'bundle.js',
    path:path.resolve(__dirname,'./build)'
    },
    module:{
        rules:[
            {
            test:/\.(png|jpeg|jpg|gif|svg)$/,
            use:[
            {
                loader:"url-loader",
                options:{
                    name:"[name].[hash:6].[ext]",
                    limit:100*1024,  
                    //限制图片大小在100k,100k以下转成base64,100k以上就不转
                }
            }
                ]
            }
          ]
        }
}

asset module type

在webpack5之前,加载这些资源我们需要使用url-loader、file-loader 在webpack5以后我们直接使用资源模块类型(asset module type),来代替上面的这些loader

asset module type通过添加4种新的模块类型,来替换这些loader:

  • asset/resource 发送一个单独的文件并导出URL,之前通过file-loader实现
  • asset/inline 导出一个资源的data URL,之前通过使用url-loader实现
  • asset/source 导处资源的源代码,之前通过raw-loader实现
  • asset 在导出一个data URL和发送一个单独的文件之间自动选择,之前通过使用url-loader并且配置资源体积实现

使用:

const path =require('path')
module.exports={
    entry:'./main.js',
    output:{'bundle.js',
    path:path.resolve(__dirname,'./build)'
    },
    module:{
        rules:[
            {
            test:/\.(png|jpeg|jpg|gif|svg)$/,
            type:"asset/resource",
            generator:{
                filename:"img/[name].[hash:6][ext]"
              }
            }
          ]
        }
}

使用asset加上体积限制

const path =require('path')
module.exports={
    entry:'./main.js',
    output:{'bundle.js',
    path:path.resolve(__dirname,'./build)'
    },
    module:{
        rules:[
            {
            test:/\.(png|jpeg|jpg|gif|svg)$/,
            type:"asset/resource",
            generator:{
                filename:"img/[name].[hash:6][ext]"
              },
            parser:{
                dataUrlCondition:{
                   maxSize:100*1024  //100kb大小的图片
                    }
                }
            }
          ]
        }
}