记一次 JSON.stringify 引起的问题

前言

目前在开发一个生成骨架屏的 webpack 插件,使用 Puppeteer 来将处理脚本经过 addScriptTag 方法来插入到页面中。webpack

想法是想模仿 webpack 能够经过配置 plugins 来添加自定义的处理规则,问题就出在这里,经过 page.evaluate 来执行页面脚本的时候获取不到我传入的 pluginsgit

问题

webpack plugin configgithub

class TestPlugin {
    apply(api, ele, options) {
        console.log(api, ele, options);
    }
}
{
    ...
    port: 8899,
    plugins: [
        function test(api, ele, options) {
            console.log(api, ele, options);
        },
        new TestPlugin()
    ],
    ...
}
复制代码

使用 puppeteer 的代码:web

await page.evaluate(options => {
  Skeleton.genSkeleton(options);
}, this.options);
复制代码

在调用 Skeleton.genSkeleton 方法的时候, options.plugins 变成了 [null, {}]。致使获取不到传递的自定义处理函数。api

排查问题

首先确认 webpack 是否接受到参数

由此能够发现 wepack 已经接受到了配置的参数

那就只能是 Puppeteer 的问题了

查看了 puppetter 的官方文档。数组

明确说明了 evaluate 方法接受的参数必须是能够被序列化的。

而后去 github 上查看它的源码发现它使用 JSON.stringify 来进行序列化。bash

那么确认是 JSON.stringify 的问题了。

进一步分析问题

既然肯定是 JSON.stringify 的问题了, 赶忙去看一波 JSON.stringify 的文档。 送上 JSON.stringify() 的MDN地址app

由此能够发现当函数出如今非数组对象时,在序列化的过程当中会被忽略,因此 plugins 第二个元素返回 {}, 当函数出如今数组对象中时,在序列化过程当中会被转换成 null,因此 plugins 的第一个元素返回 null

总结

思考一下,为何有些属性不能被 stringify 序列化。函数

由于 JSON 是一个通用的文本格式,和语言无关。设想若是将函数定义也 stringify 的话,如何判断是哪一种语言,而且经过合适的方式将其呈现出来将会变得特别复杂。特别是和语言相关的一些特性,好比 JavaScript 中的 Symbolui

ECMASCript官方也特地强调了这一点:

It does not attempt to impose ECMAScript's internal data representations on other programming languages. Instead, it shares a small subset of ECMAScript's textual representations with all other programming languages.

有兴趣的小伙伴能够了解一下如何使用 toJSON 来自定义序列化行为。

相关文章
相关标签/搜索