Skip to content

swordlib/json-partial-loader

Repository files navigation

一个 Webpack loader,用于从 JSON 文件中按键名选择性地导入部分内容。同时支持 Webpack 4 和 Webpack 5。

功能介绍

用于减小多页面项目中,减少不必要的文件大小。如可以把多语言统一放在一个json文件中,然后根据页面选择性的导入。 json-partial-loader允许你只导入 JSON 文件中的特定部分,而不是整个 JSON 对象。通过在导入语句中使用查询参数 ?key=xxx?key=xxx,yyy,zzz,你可以只提取 JSON 中对应键名的值, 多个key对象会深度合并到一个对象。

安装

# 使用 npm
npm install --save-dev @swordlib/json-partial-loader

# 使用 yarn
yarn add --dev @swordlib/json-partial-loader

# 使用 pnpm
pnpm add -D @swordlib/json-partial-loader

Webpack 配置

Webpack 5 配置

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.json$/,
        resourceQuery: /key=.+/,  // 匹配带有 key= 参数的请求
        type: 'javascript/auto',  // 防止webpack默认的json loader处理
        use: [
          {
            loader: '@swordlib/json-partial-loader',
            // 这里不需要指定options,因为我们会从resourceQuery中获取
          }
        ]
      }
    ]
  },
}; 

Webpack 4 配置

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.json$/,
        resourceQuery: /key=.+/,  // 匹配带有 key= 参数的请求
        use: [
          {
            loader: '@swordlib/json-partial-loader',
            // 这里不需要指定options,因为我们会从resourceQuery中获取
          }
        ],
        type: 'javascript/auto'  // 防止webpack默认的json loader处理
      }
    ]
  },
}; 

使用方法

假设你有一个 JSON 文件 data.json 包含以下内容:

{
  "user": {
    "name": "张三",
    "age": 30
  },
  "product": {
    "id": "p001",
    "name": "示例产品"
  },
  "settings": {
    "theme": "dark",
    "notifications": true
  },
  "metadata": {
    "version": "1.0.0",
    "lastUpdated": "2023-01-01"
  }
}

你可以这样选择性地导入特定部分:

// 分别导入 JSON 文件中不同的一级对象
import userInfo from './data.json?key=user';
import productInfo from './data.json?key=product';
import appSettings from './data.json?key=settings';
import metaData from './data.json?key=metadata';

// 打印结果
console.log('用户信息:', userInfo); // {name: "张三", age: 30}
console.log('产品信息:', productInfo); // {id: "p001", name: "示例产品"}
console.log('应用设置:', appSettings); // {theme: "dark", notifications: true}
console.log('元数据:', metaData); // {version: "1.0.0", lastUpdated: "2023-01-01"}

多键导入

你也可以通过逗号分隔的方式一次性导入多个键对应的值。当使用多键导入时,所有指定键对应对象的属性会被深度合并到一个对象中:

// 同时导入用户信息和应用设置,合并它们的属性
import userAndSettings from './data.json?key=user,settings';

// 打印结果
console.log('用户和设置:', userAndSettings);
// 输出: {
//   name: "张三", 
//   age: 30,
//   theme: "dark", 
//   notifications: true
// }

// 可以直接访问合并后的属性
console.log('用户名:', userAndSettings.name);  // 来自user对象
console.log('主题设置:', userAndSettings.theme);  // 来自settings对象

你还可以导入三个或更多的键:

// 导入三个对象并合并它们的属性
import allData from './data.json?key=user,product,settings';

// 输出: {
//   name: "张三", 
//   age: 30,
//   id: "p001", 
//   theme: "dark", 
//   notifications: true
// }

深度合并

当导入多个包含嵌套对象的键时,loader 会使用 lodash.merge 进行深度合并:

// 假设 data.json 包含以下内容:
// {
//   "user": {
//     "name": "张三",
//     "profile": {
//       "address": {
//         "city": "北京",
//         "district": "海淀区"
//       }
//     }
//   },
//   "additionalUser": {
//     "name": "李四",
//     "profile": {
//       "address": {
//         "district": "朝阳区",
//         "street": "建国路"
//       }
//     }
//   }
// }

import mergedUser from './data.json?key=user,additionalUser';

console.log(mergedUser);
// 输出: {
//   name: "李四",  // 注意这里使用了后面对象的值
//   profile: {
//     address: {
//       city: "北京",
//       district: "朝阳区",  // 注意这里使用了后面对象的值
//       street: "建国路"     // 深层属性被保留和合并
//     }
//   }
// }

工作原理

  1. 当导入 JSON 文件时,loader 会解析文件内容
  2. 解析导入语句中的查询参数 ?key=xxx?key=xxx,yyy,zzz
  3. 从 JSON 对象中提取对应键名的值
  4. 只导出该键对应的值,而不是整个 JSON 对象
  5. 当指定多个键时,会使用 lodash.merge 将所有键对应对象的属性深度合并到一个新对象中

优势

  • 性能优化:在大型 JSON 文件中,只导入需要的部分可以减少内存使用
  • 代码清晰:代码中明确表明只使用 JSON 的特定部分
  • 按需加载:在不同组件中可以只导入各自需要的数据
  • 灵活组合:可以通过多键导入组合需要的数据

注意事项

  • 确保查询参数中的键名存在于 JSON 文件中,否则将得到 undefined
  • 当使用多键导入时,如果某个键不存在,该键将被忽略
  • 当使用多键导入时,如果不同对象有同名属性,后面的键对应的属性值会覆盖前面的
  • 在深度合并时,按照 lodash.merge 的行为,数组会被完全替换而不是合并,这与对象的合并行为不同
  • 此 loader 适用于一级键的提取,不支持深层嵌套路径(如 user.profile.name

测试

本项目使用 Vitest 进行单元测试。测试覆盖了多种场景:

  • 处理没有查询参数的情况
  • 根据查询参数提取特定字段
  • 处理嵌套的 JSON 对象
  • 处理非字符串的输入(已经是对象的情况)
  • 处理不存在的键名
  • 处理数组类型的 JSON
  • 处理包含特殊字符的 JSON
  • 通过逗号分隔处理多个键
  • 在多键处理中忽略不存在的键
  • 处理复杂对象的多键提取
  • 处理有空格的多键情况
  • 处理空键名列表

运行测试:

# 安装依赖
npm install

# 运行测试
npm test

你也可以通过以下命令运行测试监视模式:

npm run test:watch

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published