From 10aa3ccb3357c049ce5ce59082c67be1295cd939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cshenyi=E2=80=9D?= <“sxm581@163.com”> Date: Thu, 5 Mar 2026 13:38:34 +0800 Subject: [PATCH] perf: use lodash tree-shaking imports instead of importing entire package Instead of: import _ from 'lodash' Use: import get from 'lodash/get' This reduces bundle size by only importing the functions actually used. Fixes issue #30 --- cache.js | 103 ++++++++++++++++++++++++++++---------------------- cache.js.new | 17 +++++++++ cacheCount.js | 18 +++++---- cacheField.js | 20 ++++++---- migrations.js | 7 ++-- 5 files changed, 103 insertions(+), 62 deletions(-) create mode 100644 cache.js.new diff --git a/cache.js b/cache.js index 884994d..29c48c3 100644 --- a/cache.js +++ b/cache.js @@ -1,5 +1,18 @@ import { addMigration, autoMigrate, migrate } from './migrations.js'; -import _ from 'lodash'; +import clone from 'lodash/clone'; +import difference from 'lodash/difference'; +import each from 'lodash/each'; +import findIndex from 'lodash/findIndex'; +import flatten from 'lodash/flatten'; +import get from 'lodash/get'; +import includes from 'lodash/includes'; +import intersection from 'lodash/intersection'; +import isEqual from 'lodash/isEqual'; +import map from 'lodash/map'; +import pick from 'lodash/pick'; +import pull from 'lodash/pull'; +import union from 'lodash/union'; +import uniq from 'lodash/uniq'; import { check, Match } from 'meteor/check'; export { migrate, autoMigrate }; @@ -7,9 +20,9 @@ export { migrate, autoMigrate }; function flattenFields(object, prefix) { prefix = prefix || ''; let fields = []; - _.each(object, (val, key) => { + each(object, (val, key) => { if (typeof val == 'object') { - fields = _.union(fields, flattenFields(val, prefix + key + '.')); + fields = union(fields, flattenFields(val, prefix + key + '.')); } else { fields.push(prefix + key); } @@ -59,15 +72,15 @@ Mongo.Collection.prototype.cache = function (options) { watchedFields = flattenFields(watchedFields); } - let childFields = _.clone(watchedFields); + let childFields = clone(watchedFields); if (type !== 'one') { - if (!_.includes(childFields, '_id')) { + if (!includes(childFields, '_id')) { childFields.push('_id'); } - _.pull(childFields, referenceField); + pull(childFields, referenceField); } let childOpts = { transform: null, fields: { _id: 0 } }; - _.each(childFields, (field) => (childOpts.fields[field] = 1)); + each(childFields, (field) => (childOpts.fields[field] = 1)); let parentOpts = { transform: null, fields: { _id: 1, [cacheField]: 1 } }; if (type !== 'inversed' && type !== 'many-inversed') { @@ -83,27 +96,27 @@ Mongo.Collection.prototype.cache = function (options) { if ( type == 'inversed' || - (type == 'many-inversed' && !_.includes(watchedFields, referencePath)) + (type == 'many-inversed' && !includes(watchedFields, referencePath)) ) { watchedFields.push(referencePath || referenceField); } - let topFields = _.uniq(watchedFields.map((field) => field.split('.')[0])); + let topFields = uniq(watchedFields.map((field) => field.split('.')[0])); function getNestedReferences(document) { //Used for nested references in "many" links - let references = _.get(document, referenceField) || []; + let references = get(document, referenceField) || []; if (idField && references.length) { - references = _.map(references, (item) => _.get(item, idField)); + references = map(references, (item) => get(item, idField)); } - return _.uniq(_.flatten(references)); + return uniq(flatten(references)); } if (type == 'one') { let insert = async function insert(userId, parent) { - if (_.get(parent, referenceField)) { + if (get(parent, referenceField)) { let child = await childCollection.findOneAsync( - _.get(parent, referenceField), + get(parent, referenceField), childOpts, ); if (child) { @@ -121,11 +134,11 @@ Mongo.Collection.prototype.cache = function (options) { parent, changedFields, ) { - if (_.includes(changedFields, referenceField.split('.')[0])) { + if (includes(changedFields, referenceField.split('.')[0])) { let child = - _.get(parent, referenceField) && + get(parent, referenceField) && (await childCollection.findOneAsync( - _.get(parent, referenceField), + get(parent, referenceField), childOpts, )); if (child) { @@ -141,7 +154,7 @@ Mongo.Collection.prototype.cache = function (options) { }); childCollection.after.insert(async function (userId, child) { - let pickedChild = _.pick(child, childFields); + let pickedChild = pick(child, childFields); await parentCollection.updateAsync( { [referenceField]: child._id }, { $set: { [cacheField]: pickedChild } }, @@ -150,11 +163,11 @@ Mongo.Collection.prototype.cache = function (options) { }); childCollection.after.update(async function (userId, child, changedFields) { - if (_.intersection(changedFields, topFields).length) { - let pickedChild = _.pick(child, childFields); + if (intersection(changedFields, topFields).length) { + let pickedChild = pick(child, childFields); // test if the object has been modified - let previousPickedChild = _.pick(this.previous, childFields); - if (!_.isEqual(previousPickedChild, pickedChild)){ + let previousPickedChild = pick(this.previous, childFields); + if (!isEqual(previousPickedChild, pickedChild)){ await parentCollection.updateAsync( { [referenceField]: child._id }, { $set: { [cacheField]: pickedChild } }, @@ -195,7 +208,7 @@ Mongo.Collection.prototype.cache = function (options) { parent, changedFields, ) { - if (_.includes(changedFields, referencePath.split('.')[0])) { + if (includes(changedFields, referencePath.split('.')[0])) { let references = getNestedReferences(parent); if (references.length) { let children = await childCollection @@ -213,7 +226,7 @@ Mongo.Collection.prototype.cache = function (options) { }); childCollection.after.insert(async function (userId, child) { - let pickedChild = _.pick(child, childFields); + let pickedChild = pick(child, childFields); await parentCollection.updateAsync( { [referencePath]: child._id }, { $push: { [cacheField]: pickedChild } }, @@ -222,12 +235,12 @@ Mongo.Collection.prototype.cache = function (options) { }); childCollection.after.update(async function (userId, child, changedFields) { - if (_.intersection(changedFields, topFields).length) { - let pickedChild = _.pick(child, childFields); + if (intersection(changedFields, topFields).length) { + let pickedChild = pick(child, childFields); await parentCollection .find({ [referencePath]: child._id }, parentOpts) .forEachAsync(async (parent) => { - let index = _.findIndex(_.get(parent, cacheField), { + let index = findIndex(get(parent, cacheField), { _id: child._id, }); if (index > -1) { @@ -268,8 +281,8 @@ Mongo.Collection.prototype.cache = function (options) { parent, changedFields, ) { - if (_.includes(changedFields, referenceField.split('.')[0])) { - if (_.get(parent, referenceField)) { + if (includes(changedFields, referenceField.split('.')[0])) { + if (get(parent, referenceField)) { let children = await childCollection .find({ [referenceField]: parent._id }, childOpts) .fetchAsync(); @@ -285,29 +298,29 @@ Mongo.Collection.prototype.cache = function (options) { }); childCollection.after.insert(async function (userId, child) { - let pickedChild = _.pick(child, childFields); - if (_.get(child, referenceField)) { + let pickedChild = pick(child, childFields); + if (get(child, referenceField)) { await parentCollection.updateAsync( - { _id: _.get(child, referenceField) }, + { _id: get(child, referenceField) }, { $push: { [cacheField]: pickedChild } }, ); } }); childCollection.after.update(async function (userId, child, changedFields) { - if (_.intersection(changedFields, topFields).length) { - let pickedChild = _.pick(child, childFields); - let previousId = this.previous && _.get(this.previous, referenceField); - if (previousId && previousId !== _.get(child, referenceField)) { + if (intersection(changedFields, topFields).length) { + let pickedChild = pick(child, childFields); + let previousId = this.previous && get(this.previous, referenceField); + if (previousId && previousId !== get(child, referenceField)) { await parentCollection.updateAsync( { _id: previousId }, { $pull: { [cacheField]: { _id: child._id } } }, ); } await parentCollection - .find({ _id: _.get(child, referenceField) }, parentOpts) + .find({ _id: get(child, referenceField) }, parentOpts) .forEachAsync(async (parent) => { - let index = _.findIndex(_.get(parent, cacheField), { + let index = findIndex(get(parent, cacheField), { _id: child._id, }); if (index > -1) { @@ -325,7 +338,7 @@ Mongo.Collection.prototype.cache = function (options) { childCollection.after.remove(async function (userId, child) { await parentCollection.updateAsync( - { _id: _.get(child, referenceField) }, + { _id: get(child, referenceField) }, { $pull: { [cacheField]: { _id: child._id } } }, ); }); @@ -347,7 +360,7 @@ Mongo.Collection.prototype.cache = function (options) { parent, changedFields, ) { - if (_.includes(changedFields, referencePath.split('.')[0])) { + if (includes(changedFields, referencePath.split('.')[0])) { let children = await childCollection .find({ [referencePath]: parent._id }, childOpts) .fetchAsync(); @@ -360,7 +373,7 @@ Mongo.Collection.prototype.cache = function (options) { childCollection.after.insert(async function (userId, child) { let references = getNestedReferences(child); if (references.length) { - let pickedChild = _.pick(child, childFields); + let pickedChild = pick(child, childFields); await parentCollection.updateAsync( { _id: { $in: references } }, { $push: { [cacheField]: pickedChild } }, @@ -370,10 +383,10 @@ Mongo.Collection.prototype.cache = function (options) { }); childCollection.after.update(async function (userId, child, changedFields) { - if (_.intersection(changedFields, topFields).length) { + if (intersection(changedFields, topFields).length) { let references = getNestedReferences(child); let previousIds = this.previous && getNestedReferences(this.previous); - previousIds = _.difference(previousIds, references); + previousIds = difference(previousIds, references); if (previousIds.length) { await parentCollection.updateAsync( { _id: { $in: previousIds } }, @@ -382,11 +395,11 @@ Mongo.Collection.prototype.cache = function (options) { ); } if (references.length) { - let pickedChild = _.pick(child, childFields); + let pickedChild = pick(child, childFields); await parentCollection .find({ _id: { $in: references } }, parentOpts) .forEachAsync(async (parent) => { - let index = _.findIndex(_.get(parent, cacheField), { + let index = findIndex(get(parent, cacheField), { _id: child._id, }); if (index > -1) { diff --git a/cache.js.new b/cache.js.new new file mode 100644 index 0000000..c99c79e --- /dev/null +++ b/cache.js.new @@ -0,0 +1,17 @@ +// Instead of: import _ from 'lodash'; +import clone from 'lodash/clone'; +import difference from 'lodash/difference'; +import each from 'lodash/each'; +import findIndex from 'lodash/findIndex'; +import flatten from 'lodash/flatten'; +import get from 'lodash/get'; +import includes from 'lodash/includes'; +import intersection from 'lodash/intersection'; +import isEqual from 'lodash/isEqual'; +import map from 'lodash/map'; +import pick from 'lodash/pick'; +import pull from 'lodash/pull'; +import union from 'lodash/union'; +import uniq from 'lodash/uniq'; + +// Then replace all _. with diff --git a/cacheCount.js b/cacheCount.js index c48e9aa..d23ef43 100644 --- a/cacheCount.js +++ b/cacheCount.js @@ -1,4 +1,8 @@ -import _ from 'lodash'; +import get from 'lodash/get'; +import intersection from 'lodash/intersection'; +import merge from 'lodash/merge'; +import union from 'lodash/union'; +import uniq from 'lodash/uniq'; import { addMigration } from './migrations.js'; import { check, Match } from 'meteor/check'; @@ -19,8 +23,8 @@ Mongo.Collection.prototype.cacheCount = function (options) { let selector = options.selector || {}; let cacheField = options.cacheField; let referenceField = options.referenceField; - let watchedFields = _.union([referenceField], Object.keys(selector)); - const topFields = _.uniq(watchedFields.map(field => field.split('.')[0])); + let watchedFields = union([referenceField], Object.keys(selector)); + const topFields = uniq(watchedFields.map(field => field.split('.')[0])); if (referenceField.split(/[.:]/)[0] == cacheField.split(/[.:]/)[0]) { throw new Error( @@ -29,9 +33,9 @@ Mongo.Collection.prototype.cacheCount = function (options) { } async function update(child) { - let ref = _.get(child, referenceField); + let ref = get(child, referenceField); if (ref) { - let select = _.merge(selector, { [referenceField]: ref }); + let select = merge(selector, { [referenceField]: ref }); await parentCollection.updateAsync( { _id: ref }, { @@ -44,7 +48,7 @@ Mongo.Collection.prototype.cacheCount = function (options) { } async function insert(userId, parent) { - let select = _.merge(selector, { [referenceField]: parent._id }); + let select = merge(selector, { [referenceField]: parent._id }); await parentCollection.updateAsync(parent._id, { $set: { [cacheField]: await childCollection.find(select).countAsync() }, }); @@ -59,7 +63,7 @@ Mongo.Collection.prototype.cacheCount = function (options) { }); childCollection.after.update(async function (userId, child, changedFields) { - if (_.intersection(changedFields, topFields).length) { + if (intersection(changedFields, topFields).length) { await update(child); await update(this.previous); } diff --git a/cacheField.js b/cacheField.js index 30c6879..ddf0187 100644 --- a/cacheField.js +++ b/cacheField.js @@ -1,4 +1,10 @@ -import _ from 'lodash'; +import compact from 'lodash/compact'; +import get from 'lodash/get'; +import includes from 'lodash/includes'; +import intersection from 'lodash/intersection'; +import map from 'lodash/map'; +import pick from 'lodash/pick'; +import uniq from 'lodash/uniq'; import { addMigration } from './migrations.js'; import { check, Match } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; @@ -17,15 +23,15 @@ Mongo.Collection.prototype.cacheField = async function (options) { : this; let cacheField = options.cacheField; let fields = options.fields; - let topFields = _.uniq(_.map(fields, (field) => field.split('.')[0])); + let topFields = uniq(map(fields, (field) => field.split('.')[0])); let transform = options.transform; if (!transform) { transform = function (doc) { - return _.compact(_.map(fields, (field) => _.get(doc, field))).join(', '); + return compact(map(fields, (field) => get(doc, field))).join(', '); }; } - if (_.includes(topFields, cacheField.split(/[.:]/)[0])) { + if (includes(topFields, cacheField.split(/[.:]/)[0])) { throw new Error( 'watching the cacheField for changes would cause an infinite loop', ); @@ -33,7 +39,7 @@ Mongo.Collection.prototype.cacheField = async function (options) { async function insertHook(userid, doc) { await collection.updateAsync(doc._id, { - $set: { [cacheField]: await transform(_.pick(doc, fields)) }, + $set: { [cacheField]: await transform(pick(doc, fields)) }, }); } @@ -42,10 +48,10 @@ Mongo.Collection.prototype.cacheField = async function (options) { collection.after.insert(insertHook); collection.after.update(function (userId, doc, changedFields) { - if (_.intersection(changedFields, topFields).length) { + if (intersection(changedFields, topFields).length) { Meteor.defer(async () => { await collection.updateAsync(doc._id, { - $set: { [cacheField]: await transform(_.pick(doc, fields)) }, + $set: { [cacheField]: await transform(pick(doc, fields)) }, }); }); } diff --git a/migrations.js b/migrations.js index f5fd97c..27649ff 100644 --- a/migrations.js +++ b/migrations.js @@ -1,4 +1,5 @@ -import _ from 'lodash'; +import clone from 'lodash/clone'; +import find from 'lodash/find'; import { Mongo } from 'meteor/mongo'; export const MigrationHistory = new Mongo.Collection('_cacheMigrations'); @@ -6,7 +7,7 @@ export const MigrationHistory = new Mongo.Collection('_cacheMigrations'); let migrations = []; export function addMigration(collection, insertFn, options) { - let opts = _.clone(options); + let opts = clone(options); if (opts.collection) { //prevent Error: Converting circular structure to JSON opts.collection = opts.collection._name; @@ -22,7 +23,7 @@ export function addMigration(collection, insertFn, options) { } export async function migrate(collectionName, cacheField, selector) { - let migration = _.find(migrations, { collectionName, cacheField }); + let migration = find(migrations, { collectionName, cacheField }); if (!migration) { throw new Error( 'no migration found for ' + collectionName + ' - ' + cacheField,