npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

uniapp-wmp-clone-with-data-patch-webpack-plugin

v1.0.0

Published

用于修复 uni-app HBuilderX 中微信小程序依赖 mp.runtime.esm.js --> cloneWithData 方法中暴力序列化的问题

Downloads

3

Readme

使用方法

  1. 安装插件 npm i -D uniapp-wmp-clone-with-data-patch-webpack-plugin
  2. 在项目根目录中添加 vue.config.js 文件并且配置插件
  3. 根据需要配置参数
// vue.config.js
const CloneWithDataPatchWebpackPlugin = require("uniapp-wmp-clone-with-data-patch-webpack-plugin");
module.exports = {
  chainWebpack: (config) => {
    config
        .plugin("cloneWithDataPatch")
        .use(CloneWithDataPatchWebpackPlugin, [
          // 【****注意****】
          // 下边这些参数都 不是必须的!! 这里写上也只是为了说明参数,并不是实际需要这样配置才行
          // 实际上,没有下列参数说明的那些情况最好不要进行任何配置
          {
            /*
              待注入方法的数组 【一般不需要修改】
                1. 方法必须包含方法名,不能是匿名方法
                2. 必须包含一个方法名叫copy的方法
                3. 这些方法在同一个平级作用域
              	4. utils.copy, utils.typeOf, utils.each 是内置的 copy 以及其依赖的方法。不满足自身需求的可以自行配置
            */
            injectMethods: [utils.copy, utils.typeOf, utils.each],
            /*
              获取说明文件输出路径的方法 【一般不需要修改】
                1. 会用此文件的存在与否来检测是否有添加过补丁
                2. 默认和 mp.runtime.esm.js 文件同级
                3. 最好是放在HBuilderX的软件目录下,这样版本更新的时候会被删除,从而通过检测重新添加补丁
                4. 可以通过 this.cwd 获取HBuilderX的Node运行时的路径
            */
            getFlagFilePath() {
              return PATH.join(this.wmpRuntimePath, "cloneWithDataPatch.txt");
            },
            /*
              获取待修复文件的路径的方法 【一般不需要修改】
                1. 应该只有在版本更新获取不到 mp.runtime.esm.js 这个文件的时候去修改为正确的路径
                2. 可以通过 this.cwd 获取HBuilderX的Node运行时的路径
            */
            getWmpRuntimeFilePath() {
              return PATH.join(this.wmpRuntimePath, "mp.runtime.esm.js");
            },
            /*
              获取待修复文件备份路径的方法 【一般不需要修改】
                1. mp.runtime.esm.js 修改前的原始文件输出路径
                2. 默认在 mp.runtime.esm.js 同级目录下
                3. 可以通过 this.cwd 获取HBuilderX的Node运行时的路径
            */
            getWmpRuntimeFileCopyPath() {
              return PATH.join(this.wmpRuntimePath, "mp.runtime.esm.js.copy.js");
            },
          },
        ]);
  },
};

相关说明

这个插件主要用于修复 uni-app 使用 HBuilderX 构建项目的时候在微信小程序端对组件 prop 采用JSON.parse(JSON.stringify(ret))暴力序列化处理,导致的prop传递的对象或者数组中包含的方法等数据被过滤的问题。参下:

// 父组件
<template>
	<v-child :data="data"></v-child>
</template>
<script>
export default {
    data(){
        return {
            // 传递 data 并且其中包含一个方法 fn
            data: {
                id: 1,
                fn(){}
            }
        }
    }
}
</script>

// 子组件
<script>
export default {
    props: {
        data: Object
    },
    mounted(){
        // 接收 data
        // 在 H5 中正常获取 fn
        // 但是在微信小程序中 fn 为 undfined
        console.log(this.data.fn); // undefined
    }
}
</script>

问题原因在于编译到微信小程序端的时候其中HBuilderX中的一个依赖项 mp.runtime.esm.js 中的 cloneWithData 方法末尾采用了 JSON.parse(JSON.stringify(ret)) 的方式去深度复制数据。参下:

// mp.runtime.esm.js
function cloneWithData(vm) {
  var ret = Object.create(null);
  var dataKeys = [].concat(
    Object.keys(vm._data || {}),
    Object.keys(vm._computedWatchers || {}));

  dataKeys.reduce(function(ret, key) {
    ret[key] = vm[key];
    return ret
  }, ret);
  var compositionApiState = vm.__composition_api_state__ || vm.__secret_vfa_state__;
  var rawBindings = compositionApiState && compositionApiState.rawBindings;
  if (rawBindings) {
    Object.keys(rawBindings).forEach(function (key) {
      ret[key] = vm[key];
    });
  }
  Object.assign(ret, vm.$mp.data || {});
  if (
    Array.isArray(vm.$options.behaviors) &&
    vm.$options.behaviors.indexOf('uni://form-field') !== -1
  ) { //form-field
    ret['name'] = vm.name;
    ret['value'] = vm.value;
  }
  // ↓↓↓↓↓↓↓↓↓↓↓↓↓也就是这句↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  return JSON.parse(JSON.stringify(ret))
}

介于自己在项目中多次遇到这个问题产生的bug,而且也没有很优雅的替代方式。

这个问题19年就有人提出过,但不知道什么原因官方一直没改,所以只能自己动手了。

原理很简单,利用 webpack 插件修改这个依赖文件的这部分代码为标准的深度复制就可以了。

每次运行和打包的时候会去检测这部分逻辑然后修改,这样就避免了更新了HBuilderX之后失效的问题。

修改后的文件参下:

// mp.runtime.esm.js
// 注入深度复制方法
function cloneWithDataPatch_copy(obj){...}
// ...
function cloneWithData(vm) {
    // ....
    // 修改 JSON.parse(JSON.stringify(ret)) 这段代码为深度复制
    return cloneWithDataPatch_copy(ret);
}