webpack实战-04-06-加载特殊类型资源

236 阅读4分钟

加载图片

使用file-loader

file-loader可以将css和js文件里面的导入图片语句替换成正确的地址,同时将文件输出到正确的位置

module.exports = {
    module: {
        rules: [
            {
                test: /\.png$/,
                use: ['file-loader']
            }
        ]
    }
}

使用url-loader

url-loader可以经过base64编码后注入js或css里面

url-loader会将根据图片内容计算出的base64编码的字符串直接注入代码中。由于一般的图片数据量巨大,会导致JavaScript/css文件也跟着变大,所以在使用url-loader时,一定要注意图片的体积不能太大,不然会导致因JavaScript/css文件过大而带来的网页加载缓慢问题。

一般啥时候用到呢,一般用它将网页需要用到的最小资源注入到代码中来减少加载次数(http/1协议中,每加载一个资源都会建立一个http链接,为了很小的资源而建立一次链接不划算)

所以!!! url-loader考虑到了以上问题,井提供了一个方便的选择:limit,该选项用于控制在文件的大小小于limit时才使用url-loader,否则使用fallback选项中配置的loader

module.exports = {
    module: {
        rules: [
            test: /\.png$/,
            use: [{
                loader: 'url-loader',
                options: {
                    // 30KB以下的文件采用url-loader
                    limit: 1024 * 30,
                    // 否则采用file-loader,默认值是file-loader
                    fallback: 'file-loader'
                }
            }]
        ]
    }
}

其他优化

  • 通过imagemin-webpack-plugin压缩图片
  • 通过webpack-ritesmith插件制作雪碧图

加载SVG(矢量图的一种标准格式)

svg的使用方法和png等一样,所以也可以使用file-loader/url-loader 介绍其他loader的使用:

使用raw-loader

raw-loader将文本的内容读取出来注入到css/js文件中

module.exports = {
    module: {
        rules: [
            {
                test: /\.svg$/,
                use: ['raw-loader']
            }
        ]
    }
}

由于raw-loader会直接返回SVG的文本内容,并且无法通过css展示SVG的文本内容,因此采用本方法后无法在css中导入SVG,也就是说,在css中不可以出现 background.image:url (./svgs/activity.svg)这样的代码,因为background-image: url (<svg>...</svg>)是不合法的

使用svg-inline-loader

和raw-loader相似,不同之处在于svg-inline-loader会分析SVG的内容,去除其中不必要的部分代码,以减小SVG的文件大小。(即增加了对SVG的压缩功能)

module.exports = {
    module: {
        rules: [
            {
                test: /\.svg$/,
                use: ['svg-inline-loader']
            }
        ]
    }
}

加载Source Map

控制Source Map输出的Webpack配置项是devtool devtool选项列表

detool含义
不生成Source Map
eval每个module会封装到eval里包裹起来执行,并且会在每个eval 吾句的末尾追加注释// # sourceURL=webpack:/// ./main.js
source-map会额外生成一个单独的Source Map文件,并且会再js文件的末尾追加// #sourceMappingURL=bundle.js.map
hidden-source-map和source-map类似,但不会再js文件末尾追加// #sourceMappingURL=bundle.js.map
inline-source-map和source-map类似,但不会额外生成一个单独的Source Map文件,而是将Source Map转换成base64编码内嵌到js中
eval-source-map和eval类似,但会将每个模块的Source Map转换成base64编码内嵌到eval语句的末尾,例如// #sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW...
cheap-source-map和source-map类似,但生成的Source Map文件中没有列信息,因此生成速度更快
cheap-module-source-map和cheap-source-map类似,但会包含Loader生成的Source Map

以上知识devtool可能取值的一部分,他的取值可以由cource-map,eval,inline,hidden,cheap,module等六个关键字随意组合完成

  • eval:用eval语句包裹需要安装的模块
  • source-map:生成独立的Source Map文件
  • hidden:不在js文件中指出Source Map文件的所在,这样浏览器就不会自动加载Source Map
  • inline:将生成的Source Map文件转换成base64格式内嵌再js文件中
  • cheap:在生成的Source Map中不会包含列信息,这样计算量更小,输出的Source Map文件更小,同时Loader输出的Source Map不会被采用
  • module:来自Loader的Source Map被简单处理成每行一个的模块

如何选择(毕竟那么多组合)

如果不关心细节和性能,只是想在不出任何差错的情况下调试源码,则可以直接设置成source map,但这样会造成以下两个问题。

  • 在source-map模式下会输出质量最高且最详细的Source Map,这回造成构建速度缓慢,特别是在开发过程中需要频繁修改时会增加等待时间
  • 在source-map模式下会将Source Map暴露,若构建发布到线上的代码的Source Map暴露,就等同于源码被泄漏

为了解决以上两个问题:

  • 在开发环境下将devtool设置成cheap-module-eval-source-map,因为生成这种Source Map的速度最快,能加速构建,由于在开发环境下不会做代码压缩,所以在Source Map中即使没有列信息,也不会影响断点调试
  • 在生产环境下将devtool设置成hidden-source-map,生成最详细的Source Map,但不会将Source Map暴露出去,由于在生产环境下会做代码压缩,一个js文件只有一行,所以需要列信息。

生产环境下通常不会把Source Map上传到HTTP服务器让用户获取,而是上传到js错误收集系统,在错误收集系统上根据Source Map和收集到的js运行错误堆栈,计算出错误所在远吗位置 不要在生产环境下使用inline模式的Source Map,这回导致js文件变得很大,且会泄漏源码

加载现有的Source Map

某些从Npm安装的第三方模块是采用ES6或者TypeScript编写的,它们在发布时会同时带上编译出来的JavaScript文件和对应的Source Map文件,以方便我们在使用它们出问题时进行调试

在默认情况下,Webpack不会加载这些附加的Source Map文件,Webpack只会在转换的过程中生成Source Map。这时需要使用source-map-loader让 Webpack 加载这些附加的 Source Map 文件

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                // 只加载我们关心的目录下的Source Map,以提升构建速度
                indlude: [path.resolve(root, 'node_modules/some-components/')],
                // 将source-map-loader执行顺序放在最前面,怕再source-map-loader之前有loader转换了该js文件,会导致Source Map映射错误
                enforce: 'pre'
            }
        ]
    }
}