@cocreate/lazy-loader 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/package.json +2 -2
- package/src/client.js +61 -0
- package/src/index.js +13 -60
- package/src/server.js +184 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
# [1.10.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.9.0...v1.10.0) (2023-12-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* get config using CoCreate-config ([8e0b9fc](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/8e0b9fce220c493a1db250cf424345d7708a2e08))
|
|
7
|
+
* lazyload client and server modules ([80e25d6](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/80e25d67d729eaec18775a43bf1ef10cb9141aa8))
|
|
8
|
+
|
|
9
|
+
# [1.9.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.8.0...v1.9.0) (2023-11-25)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* upgrade dependencies for latest features and fixes ([bc5e0b5](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/bc5e0b5a622f9bc871ef18914f6d7466d5a05a30))
|
|
15
|
+
|
|
1
16
|
# [1.8.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.7.0...v1.8.0) (2023-11-25)
|
|
2
17
|
|
|
3
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/lazy-loader",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "A simple lazy-loader component in vanilla javascript. Easily configured using HTML5 data-attributes and/or JavaScript API.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lazy-loader",
|
|
@@ -58,6 +58,6 @@
|
|
|
58
58
|
"webpack-log": "^3.0.1"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@cocreate/observer": "^1.
|
|
61
|
+
"@cocreate/observer": "^1.14.0"
|
|
62
62
|
}
|
|
63
63
|
}
|
package/src/client.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import observer from '@cocreate/observer';
|
|
2
|
+
|
|
3
|
+
function listen(callback, selector) {
|
|
4
|
+
|
|
5
|
+
function observerCallback({ target }) {
|
|
6
|
+
// let isInit = target.querySelector(selector)/testtt
|
|
7
|
+
// if (isInit) {
|
|
8
|
+
callback()
|
|
9
|
+
// console.log('lazyloaded', selector)
|
|
10
|
+
observer.uninit(observerCallback)
|
|
11
|
+
// }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
observer.init({
|
|
15
|
+
name: 'lazyloadObserver',
|
|
16
|
+
observe: ['childList'],
|
|
17
|
+
target: selector,
|
|
18
|
+
callback: observerCallback
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
let selectorAttributes = [];
|
|
22
|
+
let attributes = selector.split(",")
|
|
23
|
+
for (let attribute of attributes) {
|
|
24
|
+
let attr = attribute.trim()
|
|
25
|
+
if (attr.startsWith("[")) {
|
|
26
|
+
let pos = attr.indexOf("*")
|
|
27
|
+
if (pos == -1)
|
|
28
|
+
pos = attr.indexOf("=")
|
|
29
|
+
if (pos !== -1) {
|
|
30
|
+
attr = attr.slice(1, pos)
|
|
31
|
+
} else {
|
|
32
|
+
attr = attr.slice(1, -1)
|
|
33
|
+
}
|
|
34
|
+
selectorAttributes.push(attr)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
if (selectorAttributes.length > 0)
|
|
39
|
+
observer.init({
|
|
40
|
+
name: 'lazyloadAttributeObserver',
|
|
41
|
+
observe: ['attributes'],
|
|
42
|
+
attributeName: selectorAttributes,
|
|
43
|
+
target: selector,
|
|
44
|
+
callback: observerCallback
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function lazyLoad(name, selector, callback) {
|
|
50
|
+
if (document.querySelector(selector))
|
|
51
|
+
await dependency(name, await callback())
|
|
52
|
+
else
|
|
53
|
+
listen(callback, selector)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function dependency(name, promise) {
|
|
57
|
+
let component = await promise;
|
|
58
|
+
Object.assign(window.CoCreate, {
|
|
59
|
+
[name]: component.default
|
|
60
|
+
});
|
|
61
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,61 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
function observerCallback({ target }) {
|
|
6
|
-
// let isInit = target.querySelector(selector)
|
|
7
|
-
// if (isInit) {
|
|
8
|
-
callback()
|
|
9
|
-
// console.log('lazyloaded', selector)
|
|
10
|
-
observer.uninit(observerCallback)
|
|
11
|
-
// }
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
observer.init({
|
|
15
|
-
name: 'lazyloadObserver',
|
|
16
|
-
observe: ['childList'],
|
|
17
|
-
target: selector,
|
|
18
|
-
callback: observerCallback
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
let selectorAttributes = [];
|
|
22
|
-
let attributes = selector.split(",")
|
|
23
|
-
for (let attribute of attributes) {
|
|
24
|
-
let attr = attribute.trim()
|
|
25
|
-
if (attr.startsWith("[")) {
|
|
26
|
-
let pos = attr.indexOf("*")
|
|
27
|
-
if (pos == -1)
|
|
28
|
-
pos = attr.indexOf("=")
|
|
29
|
-
if (pos !== -1) {
|
|
30
|
-
attr = attr.slice(1, pos)
|
|
31
|
-
} else {
|
|
32
|
-
attr = attr.slice(1, -1)
|
|
33
|
-
}
|
|
34
|
-
selectorAttributes.push(attr)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
if (selectorAttributes.length > 0)
|
|
39
|
-
observer.init({
|
|
40
|
-
name: 'lazyloadAttributeObserver',
|
|
41
|
-
observe: ['attributes'],
|
|
42
|
-
attributeName: selectorAttributes,
|
|
43
|
-
target: selector,
|
|
44
|
-
callback: observerCallback
|
|
1
|
+
(function (root, factory) {
|
|
2
|
+
if (typeof define === 'function' && define.amd) {
|
|
3
|
+
define(["./client"], function (CoCreateLazyLoader) {
|
|
4
|
+
return factory(CoCreateLazyLoader)
|
|
45
5
|
});
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export async function dependency(name, promise) {
|
|
57
|
-
let component = await promise;
|
|
58
|
-
Object.assign(window.CoCreate, {
|
|
59
|
-
[name]: component.default
|
|
60
|
-
});
|
|
61
|
-
}
|
|
6
|
+
} else if (typeof module === 'object' && module.exports) {
|
|
7
|
+
const CoCreateLazyLoader = require("./server.js")
|
|
8
|
+
module.exports = factory(CoCreateLazyLoader);
|
|
9
|
+
} else {
|
|
10
|
+
root.returnExports = factory(root["./client.js"]);
|
|
11
|
+
}
|
|
12
|
+
}(typeof self !== 'undefined' ? self : this, function (CoCreateLazyLoader) {
|
|
13
|
+
return CoCreateLazyLoader;
|
|
14
|
+
}));
|
package/src/server.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const EventEmitter = require('events');
|
|
2
|
+
const eventEmitter = new EventEmitter();
|
|
3
|
+
const fs = require('fs').promises;
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const vm = require('vm');
|
|
6
|
+
const Config = require("@cocreate/config");
|
|
7
|
+
|
|
8
|
+
class CoCreateLazyLoader {
|
|
9
|
+
constructor(crud) {
|
|
10
|
+
this.wsManager = crud.wsManager
|
|
11
|
+
this.crud = crud
|
|
12
|
+
this.exclusion = { ...require.cache };
|
|
13
|
+
this.modules = {};
|
|
14
|
+
this.init()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async init() {
|
|
18
|
+
// Function to create the scripts directory if it doesn't exist
|
|
19
|
+
async function createScriptsDirectory() {
|
|
20
|
+
try {
|
|
21
|
+
const scriptsDirectory = './scripts';
|
|
22
|
+
await fs.mkdir(scriptsDirectory, { recursive: true });
|
|
23
|
+
console.log(`Scripts directory created at ${scriptsDirectory}`);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error('Error creating scripts directory:', error);
|
|
26
|
+
throw error; // Halt execution if directory creation fails
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Call this function at the start of your application
|
|
31
|
+
createScriptsDirectory();
|
|
32
|
+
|
|
33
|
+
const config = await Config('lazyload', false, false)
|
|
34
|
+
if (!config)
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
for (let key of Object.keys(config.lazyload)) {
|
|
38
|
+
let moduleConfig = config.lazyload[key];
|
|
39
|
+
eventEmitter.on(moduleConfig.event, async () => {
|
|
40
|
+
this.executeScriptWithTimeout(key, moduleConfig)
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// eventEmitter.emit('openai');
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async executeScriptWithTimeout(moduleName, moduleConfig) {
|
|
49
|
+
try {
|
|
50
|
+
if (!moduleConfig.content) {
|
|
51
|
+
if (moduleConfig.path)
|
|
52
|
+
moduleConfig.content = await require(moduleConfig.path)
|
|
53
|
+
else {
|
|
54
|
+
try {
|
|
55
|
+
const scriptPath = path.join(scriptsDirectory, `${moduleName}.js`);
|
|
56
|
+
await fs.access(scriptPath);
|
|
57
|
+
moduleConfig.content = await fs.readFile(scriptPath, 'utf8');
|
|
58
|
+
} catch {
|
|
59
|
+
moduleConfig.content = await fetchScriptFromDatabaseAndSave(moduleName, moduleConfig);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (moduleConfig.unload === false || moduleConfig.unload === 'false')
|
|
65
|
+
return
|
|
66
|
+
else if (moduleConfig.unload === true || moduleConfig.unload === 'true')
|
|
67
|
+
console.log('config should unload after completeion ')
|
|
68
|
+
else if (moduleConfig.unload = parseInt(moduleConfig.unload, 10)) {
|
|
69
|
+
// Check if the script is already loaded
|
|
70
|
+
if (moduleConfig.timeout) {
|
|
71
|
+
clearTimeout(moduleConfig.timeout);
|
|
72
|
+
} else if (!moduleConfig.path) {
|
|
73
|
+
// Execute the script
|
|
74
|
+
moduleConfig.context = new vm.createContext({});
|
|
75
|
+
const script = new vm.Script(moduleConfig.context);
|
|
76
|
+
script.runInContext(context);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Reset or set the timeout
|
|
80
|
+
const timeout = setTimeout(() => {
|
|
81
|
+
delete this.modules[moduleName]
|
|
82
|
+
delete moduleConfig.timeout
|
|
83
|
+
delete moduleConfig.context
|
|
84
|
+
delete moduleConfig.content
|
|
85
|
+
console.log(`Module ${moduleName} removed due to inactivity.`);
|
|
86
|
+
clearModuleCache(moduleName);
|
|
87
|
+
|
|
88
|
+
}, moduleConfig.unload);
|
|
89
|
+
|
|
90
|
+
moduleConfig.timeout = timeout
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.log(error)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getModuleDependencies(modulePath) {
|
|
100
|
+
let moduleObj = require.cache[modulePath];
|
|
101
|
+
if (!moduleObj) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Get all child module paths
|
|
106
|
+
return moduleObj.children.map(child => child.id);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function isModuleUsedElsewhere(modulePath, moduleName) {
|
|
110
|
+
return Object.keys(require.cache).some(path => {
|
|
111
|
+
const moduleObj = require.cache[path];
|
|
112
|
+
// return moduleObj.children.some(child => child.id === modulePath && path !== modulePath);
|
|
113
|
+
return moduleObj.children.some(child => {
|
|
114
|
+
// let test = child.id === modulePath && path !== modulePath
|
|
115
|
+
// if (test)
|
|
116
|
+
// return test
|
|
117
|
+
return child.id === modulePath && path !== modulePath
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function clearModuleCache(moduleName) {
|
|
123
|
+
try {
|
|
124
|
+
const modulePath = require.resolve(moduleName);
|
|
125
|
+
const dependencies = getModuleDependencies(modulePath);
|
|
126
|
+
|
|
127
|
+
// Check if the module is a dependency of other modules
|
|
128
|
+
// const moduleObj = require.cache[modulePath];
|
|
129
|
+
// if (moduleObj && moduleObj.parent) {
|
|
130
|
+
// console.log(`Module ${moduleName} is a dependency of other modules.`);
|
|
131
|
+
// return;
|
|
132
|
+
// }
|
|
133
|
+
|
|
134
|
+
// Check if the module is used by other modules
|
|
135
|
+
if (isModuleUsedElsewhere(modulePath, moduleName)) {
|
|
136
|
+
console.log(`Module ${moduleName} is a dependency of other modules.`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Remove the module from the cache
|
|
141
|
+
delete require.cache[modulePath];
|
|
142
|
+
console.log(`Module ${moduleName} has been removed from cache.`);
|
|
143
|
+
// Recursively clear dependencies from cache
|
|
144
|
+
dependencies.forEach(depPath => {
|
|
145
|
+
clearModuleCache(depPath);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error(`Error clearing module cache for ${moduleName}: ${error.message}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Function to fetch script from database and save to disk
|
|
154
|
+
async function fetchScriptFromDatabaseAndSave(moduleName, moduleConfig) {
|
|
155
|
+
let data = {
|
|
156
|
+
method: 'object.read',
|
|
157
|
+
array: moduleConfig.array,
|
|
158
|
+
$filter: {
|
|
159
|
+
query: [
|
|
160
|
+
{ key: "host", value: [moduleConfig.object.hostname, '*'], operator: "$in" },
|
|
161
|
+
{ key: "pathname", value: moduleConfig.object.pathname, operator: "$eq" }
|
|
162
|
+
],
|
|
163
|
+
limit: 1
|
|
164
|
+
},
|
|
165
|
+
organization_id
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
let file = await crud.send(data);
|
|
169
|
+
let src;
|
|
170
|
+
|
|
171
|
+
if (file && file.object && file.object[0]) {
|
|
172
|
+
src = file.object[0].src;
|
|
173
|
+
} else {
|
|
174
|
+
throw new Error('Script not found in database');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Save to disk for future use
|
|
178
|
+
const scriptPath = path.join(scriptsDirectory, `${moduleName}.js`);
|
|
179
|
+
await fs.writeFile(scriptPath, src);
|
|
180
|
+
|
|
181
|
+
return src;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = CoCreateLazyLoader;
|