webpack实战——生产环境配置【中】

2020-09-24 15:29:07 浏览数 (1)

前言

上一篇中,描述了一些关于生产环境的配置:环境变量的使用、配置文件描述、开启生产模式、环境变量自定义配置等,从这几个方面入手都可以对生产环境产生一些有利影响。

那么本篇,从source map资源压缩方面入手,继续深入探究。

1. source map

“source map 指的是将编译、打包、压缩后的代码映射回源代码的过程。

经过webpack打包压缩后的代码基本上已经不具备可读性,此时若是代码抛出错误,想要回溯它的调用栈是非常困难的,而有了source map,加上浏览器调试工具(dev tools),要做到这一点就会变得很容易。同时,它对于线上问题的追查也有一定帮助。

1.1 原理

工作原理:webpack对于工程源代码的每一步处理都有可能会改变代码的位置、结构、甚至是所处文件,因此每一步都需要生成对应的source map。如果我们启用了devtool配置,那么source map就会跟随源代码一步步被传递,直到生成最后的map文件。这个文件默认就是打包后的文件名字上加上后缀[.map],例如bundle.js.map。

在生成map文件的同时,bundle文件中会追加一句注释来标识map文件的位置,例如:

代码语言:javascript复制
// bundle.js
(function() {
    // bundle的内容
    ...
})()
// # sourceMappingURL=bundle.js.map

而当我们打开浏览器开发者工具后,其实map文件同时也会被加载进来,这时浏览器会使用它来对打包后的bundle文件来进行解析,分析出源代码的目录结构和内容。

亲自尝试过的朋友可能会发现,打包后,map文件会比较大,甚至超出源文件几倍的体积大小,不过不用担心,不打开开发者工具是不会加载这些map文件的,因此对于普通用户来讲没有什么影响。但是要注意的是,虽然普通用户看不到,不过有经验的“特殊人群”还是可以通过dev tools看到工程源码的。因此建议如果是生产环境,还是要解决一下。如何解决呢?下面会提到。

1.2 配置

在webpack.config.js中添加devtool即可完成对source map的配置。

代码语言:javascript复制
// webpack.config.js
module.exports = {
    // ...
    devtool: 'source-map'
}

而对于CSS、SCSS及Less来说,则需要添加额外的source map配置项。如:

代码语言:javascript复制
const path = require('path');
module.exports = {
    // ...
    devtool: 'source-map',
    module: {
        rules: [
            // scss
            {
                test: /.scss$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: true,
                        }
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: true
                        }
                    }
                ]
            }
        ]
    }
}

webpack给出多种source map形式:

  • source-map
  • cheap-source-map
  • eval-source-map
  • ...

在开发环境中,通常使用module-eval-source-map,因为在打包速度和源码信息还原程度都属于良好程度。

而在生产环境中,通常我们会对代码进行压缩,而最常见的压缩插件UglifyjsWebpackPlugin目前只支持source-map形式。

1.3 安全

在1.1中我们抛出一个安全问题,就是在开启source-map的时候任何人都可以通过浏览器的开发者工具devtool来看到工程源码,因此对于安全性来讲是一个极大的隐患。那么如何能在保持其功能的同时又能防止暴漏源码呢?

webpack提供了两种安全策略:

  1. hidden-source-map
  2. nosources-source-map

hidden-source-map

hidden-source-map意味着Webpack仍然会产出完整的map文件,但是不会在bundle文件中添加对于map文件的引用。这样当打开浏览器开发者工具时,是无法看到map文件的,自然也就无法解析。如果我们自己想要追溯源码,可使用一些第三方服务,将map文件上传到第三方服务中。目前比较流行的是Sentry(错误跟踪平台),有兴趣的可以自行搜索了解一下。

nosources-source-map

它对于安全性保护不如hidden-source-map,但是使用方式相对简单。当打包部署后,我们可以在浏览器开发者工具的sources选项卡中看到源码的目录结构,但是文件内容会被隐藏起来。这样,对于错误来讲,我们仍然可以在console控制台中查看源代码的错误栈,或者console日志的准确行数。对于追溯错误来说基本上够使用。

另外的方案则是服务端配合处理,例如正常打包出source map,服务端通过服务器的nginx配置,将.map文件只对固定的白名单(如公司内网)开放,这样其余用户就无法获取到它们了,也不失为一个小妙招。

2. 资源压缩

“资源在发布到生产环境之前,通常会进行代码压缩,也叫uglify,意思是移除多余的空格、换行、执行不到的代码块等,同时缩短变量名,在执行结果不变的前提下替换为更短的形式。

一般工程代码在被压缩后整个体积会显著缩小。

但同时,uglify之后的代码基本上不具有可读性,从另一个层面讲,一定程度上提高了代码的安全性

2.1 压缩JavaScript

压缩JS(JavaScript)的工具terser(optomization)在webpack中已集成(webpack4),并且支持ES6 的代码压缩,偏面向未来。

示例:

代码语言:javascript复制
// webpack.config.js
module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js'
    },
    // 压缩配置
    optomization: {
        minimize: true
    }
}

2.2 压缩CSS

CSS文件的压缩前提是使用相关插件处理,先将样式提取出来,然后进行压缩。例如 常使用extract-text-webpack-plugin或mini-css-extract-plugin将样式提取,然后使用optimize-css-assets-webpack-plugin来进行压缩。 这个插件本质上使用的是压缩器cssnano,当然我们可以对其进行配置:

代码语言:javascript复制
// webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: 'css-loader'
                })
            }
        ]
    },

    // css 压缩
    plugins: [new ExtractTextPlugin('style.css')];
    optimization: {
        minimizer: [new OptimizeCssAssetsPlugin({
            // 生效范围,只压缩匹配到的资源
            assetNameRegExp: /.optimize.css$/g,
            // 压缩处理器指定,默认为 cssnano
            cssProcessor: require('cssnano'),
            // 压缩处理器配置
            cssProcessorOptions: {
                discardComments: {
                    removeAll: true
                }
            },
            // 是否打印log
            canPrint: true
        })]
    }
}

小结

本篇介绍了关于生产环境配置中比较重量级的两种配置:source-map和资源压缩。

开发环境中我们关注打包速度,而在生产环境中我们关心的则是线上错误处理、输出资源的体积以及资源渲染等问题,而比较好的利用source-map和资源压缩都可以帮助我们处理处理或优化生产环境中的一些问题,因此比较重要,但同时也要注意解决所存在的安全隐患问题。

下一篇则从缓存和bundle体积监控入手继续描述生产环境配置的其他方面优化问题。

0 人点赞