webpack源码解析五

前言

我们继续前面的内容,把webpack剩下的配置项撸一遍,推荐大家先看一下前面的文章:

配置

devtool

此选项控制是否生成,以及如何生成 source map。

什么是Source map?

简单说,Source map就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置(source map更多的介绍跟怎么使用就不在这里分析了)

string or false

选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。

webpack 仓库中包含一个 显示所有 devtool 变体效果的示例。这些例子或许会有助于你理解这些差异之处。

你可以直接使用 SourceMapDevToolPlugin/EvalSourceMapDevToolPlugin 来替代使用 devtool 选项,因为它有更多的选项。切勿同时使用 devtool 选项和 SourceMapDevToolPlugin/EvalSourceMapDevToolPlugin 插件。devtool 选项在内部添加过这些插件,所以你最终将应用两次插件。

devtool 构建速度 重新构建速度 生产环境 品质(quality)
(none) fastest fastest yes 打包后的代码
eval fastest fastest no 生成后的代码
eval-cheap-source-map fast faster no 转换过的代码(仅限行)
eval-cheap-module-source-map slow faster no 原始源代码(仅限行)
eval-source-map slowest fast no 原始代码
eval-nosources-source-map
eval-nosources-cheap-source-map
eval-nosources-cheap-module-source-map
cheap-source-map fast slow yes 转换过的代码(仅限行)
cheap-module-source-map slow slower yes 原始源代码(仅限行)
inline-cheap-source-map fast slow no 转换过的代码(仅限行)
inline-cheap-module-source-map slow slower no 原始源代码(仅限行)
inline-source-map slowest slowest no 原始代码
inline-nosources-source-map
inline-nosources-cheap-source-map
inline-nosources-cheap-module-source-map
source-map slowest slowest yes 原始代码
hidden-source-map slowest slowest yes 原始代码
hidden-nosources-source-map
hidden-nosources-cheap-source-map
hidden-nosources-cheap-module-source-map
hidden-cheap-source-map
hidden-cheap-module-source-map
nosources-source-map slowest slowest yes 无源代码内容
nosources-cheap-source-map
nosources-cheap-module-source-map

其中一些值适用于开发环境,一些适用于生产环境。对于开发环境,通常希望更快速的 source map,需要添加到 bundle 中以增加体积为代价,但是对于生产环境,则希望更精准的 source map,需要从 bundle 中分离并独立存在。

Chrome 中的 source map 有一些问题。我们需要你的帮助!

查看 output.sourceMapFilename 自定义生成的 source map 的文件名。

品质说明(quality)

打包后的代码 - 将所有生成的代码视为一大块代码。你看不到相互分离的模块。

生成后的代码 - 每个模块相互分离,并用模块名称进行注释。可以看到 webpack 生成的代码。示例:你会看到类似 var module__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(42); module__WEBPACK_IMPORTED_MODULE_1__.a();,而不是 import {test} from "module"; test();

转换过的代码 - 每个模块相互分离,并用模块名称进行注释。可以看到 webpack 转换前、loader 转译后的代码。示例:你会看到类似 import {test} from "module"; var A = function(_test) { ... }(test);,而不是 import {test} from "module"; class A extends test {}

原始源代码 - 每个模块相互分离,并用模块名称进行注释。你会看到转译之前的代码,正如编写它时。这取决于 loader 支持。

无源代码内容 - source map 中不包含源代码内容。浏览器通常会尝试从 web 服务器或文件系统加载源代码。你必须确保正确设置 output.devtoolModuleFilenameTemplate,以匹配源代码的 url。

(仅限行) - source map 被简化为每行一个映射。这通常意味着每个语句只有一个映射(假设你使用这种方式)。这会妨碍你在语句级别上调试执行,也会妨碍你在每行的一些列上设置断点。与压缩后的代码组合后,映射关系是不可能实现的,因为压缩工具通常只会输出一行。

对于开发环境

以下选项非常适合开发环境:

eval - 每个模块都使用 eval() 执行,并且都有 //@ sourceURL。此选项会非常快地构建。主要缺点是,由于会映射到转换后的代码,而不是映射到原始代码(没有从 loader 中获取 source map),所以不能正确的显示行数。

eval-source-map - 每个模块使用 eval() 执行,并且 source map 转换为 DataUrl 后添加到 eval() 中。初始化 source map 时比较慢,但是会在重新构建时提供比较快的速度,并且生成实际的文件。行数能够正确映射,因为会映射到原始代码中。它会生成用于开发环境的最佳品质的 source map。

cheap-eval-source-map - 类似 eval-source-map,每个模块使用 eval() 执行。这是 “cheap(低开销)” 的 source map,因为它没有生成列映射(column mapping),只是映射行数。它会忽略源自 loader 的 source map,并且仅显示转译后的代码,就像 eval devtool。

cheap-module-eval-source-map - 类似 cheap-eval-source-map,并且,在这种情况下,源自 loader 的 source map 会得到更好的处理结果。然而,loader source map 会被简化为每行一个映射(mapping)。

特定场景

以下选项对于开发环境和生产环境并不理想。他们是一些特定场景下需要的,例如,针对一些第三方工具。

inline-source-map - source map 转换为 DataUrl 后添加到 bundle 中。

cheap-source-map - 没有列映射(column mapping)的 source map,忽略 loader source map。

inline-cheap-source-map - 类似 cheap-source-map,但是 source map 转换为 DataUrl 后添加到 bundle 中。

cheap-module-source-map - 没有列映射(column mapping)的 source map,将 loader source map 简化为每行一个映射(mapping)。

inline-cheap-module-source-map - 类似 cheap-module-source-map,但是 source mapp 转换为 DataUrl 添加到 bundle 中。

对于生产环境

这些选项通常用于生产环境中:

(none)(省略 devtool 选项) - 不生成 source map。这是一个不错的选择。

source-map - 整个 source map 作为一个单独的文件生成。它为 bundle 添加了一个引用注释,以便开发工具知道在哪里可以找到它。

你应该将你的服务器配置为,不允许普通用户访问 source map 文件!

hidden-source-map - 与 source-map 相同,但不会为 bundle 添加引用注释。如果你只想 source map 映射那些源自错误报告的错误堆栈跟踪信息,但不想为浏览器开发工具暴露你的 source map,这个选项会很有用。

你不应将 source map 文件部署到 web 服务器。而是只将其用于错误报告工具。

nosources-source-map - 创建的 source map 不包含 sourcesContent(源代码内容)。它可以用来映射客户端上的堆栈跟踪,而无须暴露所有的源代码。你可以将 source map 文件部署到 web 服务器。

这仍然会暴露反编译后的文件名和结构,但它不会暴露原始代码。

在使用 uglifyjs-webpack-plugin你必须提供 sourceMap:true 选项来启用 source map 支持。


以上是官网的描述,我们大概知道了sourcemap这个东西,下面我们结合demo对几个常用的devtool做一下测试。

eval(默认)

打包过后的代码。

对应配置文件,

webpack.config.js:

const path = require("path");
module.exports = {
   
    mode: "development",
    context: path.resolve(__dirname, "./src"),
    // entry: ["babel-polyfill","./index.js"]
    entry: {
   
        app: ["./index.js"]
    },
    output: {
   
        path: path.join(process.cwd(), "lib"), //默认为path.join(process.cwd(), "dist")
        pathinfo: true,
        filename: "[name].[contenthash:16].[fullhash:16].[id].js",
        chunkFilename: "[id].js",
        // library: "demoSay",
        // libraryExport: "default",
        // libraryTarget: "jsonp",

    },
    experiments: {
   
        // outputModule: true
    },
    module: {
   
        noParse: /babel-polyfill/,
        rules: [
            {
   
                test: /.vue$/,
                use: 'vue-loader',
            },
            {
   
                test: /\.(sass|scss)$/,
                use: [
                    "style-loader",
                    "css-loader",
                    {
   
                        loader: "postcss-loader",
                        options: {
   
                            config: {
   
                                path: path.resolve(__dirname, "./postcss.config.js")
                            }
                        }
                    },
                    "sass-loader"
                ],
            },
            {
   
                test: /\.png$/,
                oneOf: [
                    {
   
                        resourceQuery: /inline/,
                        loader: "url-loader",
                        options: {
   
                            limit: 1024 * 1024 * 10
                        }
                    },
                    {
   
                        resourceQuery: /external/,
                        loader: "file-loader",
                    }
                ]
            }
        ]
    },
    resolve: {
   
        alias: {
   
            DemoVue: path.resolve(__dirname, "./src/demo-vue.vue")
        },
        extensions: ['.wasm', '.mjs', '.js', '.json', '.vue'],
        modules: [path.resolve(__dirname, "src"), "node_modules"],
        unsafeCache: /demo-publicpath/,
    },
    plugins: [
        new (require("vue-loader-plugin"))()
    ],
    devServer: {
   
        before(app, server, compiler) {
   
            app.get("/login",(req,res,next)=>{
   
                req.query.name="hello "+req.query.name;
                next();
            });
        },
        after(app, server, compiler) {
   
            app.get("/login",(req,res,next)=>{
   
                res.json({
   msg: req.query.name});
            });
        },
        clientLogLevel: "info",
        allowedHosts: [
            "localhost"
        ],
        contentBase: path.join(process.cwd(), "lib"),
        // contentBasePublicPath: "/assets",
        filename: /app\.js/,
        headers: {
   
            'X-Custom-Foo': 'bar'
        },
        historyApiFallback: true,
        host: "0.0.0.0",
        port: "8090",
        hot: true,
        liveReload: false,
        open: true,
        useLocalIp: true,
        overlay: true,
        publicPath: "/dist/"
    },
    devtool: "eval"
};

然后运行webpack-dev-server:

192:webpack-demo yinqingyang$ node ./node_modules/webpack/node_modules/.bin/webpack-dev-server

然后访问入口文件:http://192.168.2.103:8090/dist/app.dce652981f001848.1b5476d5f9831bfb.app

在这里插入图片描述

可以看到,浏览器中显示了我们打包过后的文件,比如index.js:

__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _demo_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo-vue */ "./demo-vue.vue");
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vue */ "../node_modules/vue/dist/vue.runtime.esm.js");
/* harmony import */ var demo_publicpath__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! demo-publicpath */ "./demo-publicpath.js");
__webpack_require__.p = "/";



const root=document.createElement("div");
root.id="app";
document.body.appendChild(root)
const app=new vue__WEBPACK_IMPORTED_MODULE_1__.default({
   
    render:(h)=>h(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值