@pinegrow/vite-plugin 3.0.0-beta.5 → 3.0.0-beta.50

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.
@@ -0,0 +1,328 @@
1
+ import { onBeforeMount, onMounted, onBeforeUnmount, getCurrentInstance, ref, reactive, computed } from 'vue'
2
+
3
+ export function usePinegrow() {
4
+ const initCache = () => {
5
+ // conditional
6
+ const winObj = window
7
+
8
+ if (!(winObj?.process?.client && winObj.process.client !== true)) {
9
+ if (!winObj.pinegrow) {
10
+ // conditional
11
+ // console.log('Cache initialized by Pinegrow Vue Plugin!')
12
+ const elCache = reactive(new Map())
13
+
14
+ // const enRichWithComponentName = elCacheObj => {
15
+ // return {
16
+ // name:
17
+ // getComponentName(elCacheObj.instance.type, elCacheObj.localFile) +
18
+ // `${elCacheObj.key !== undefined && elCacheObj.key !== null ? ` (${elCacheObj.key})` : ''}`,
19
+ // ...elCacheObj,
20
+ // }
21
+ // }
22
+
23
+ const enRichWithComponentName = elCacheObj => {
24
+ return {
25
+ name: elCacheObj.instance.type.__name || '',
26
+ ...elCacheObj,
27
+ }
28
+ }
29
+
30
+ const rootFragmentToPgIdComputed = computed(() => {
31
+ const rootEls = new Map()
32
+ for (let [key, value] of elCache.entries()) {
33
+ if (value.instance.isMounted && !value.instance.isUnmounted && value.isRootFragment) {
34
+ rootEls.set(key, value)
35
+ }
36
+ }
37
+ return rootEls
38
+ })
39
+
40
+ const pgIdToElComputed = computed(() => {
41
+ const pgIds = {}
42
+ for (let [key, value] of elCache.entries()) {
43
+ if (
44
+ value.instance.isMounted &&
45
+ !value.instance.isUnmounted &&
46
+ value.pgIds &&
47
+ value.pgIds.length &&
48
+ (!value.rootEl || value.isRootFragment)
49
+ ) {
50
+ value.pgIds.forEach(pgId => {
51
+ if (!pgIds[pgId]) {
52
+ pgIds[pgId] = []
53
+ }
54
+ if (value.key === undefined || value.key === null) {
55
+ pgIds[pgId].push(value)
56
+ } else {
57
+ pgIds[pgId].push([value.key, value])
58
+ }
59
+ })
60
+ }
61
+ }
62
+ return pgIds
63
+ })
64
+
65
+ const localComponentToElComputed = computed(() => {
66
+ const localComponents = {}
67
+ for (let [key, value] of elCache.entries()) {
68
+ if (
69
+ value.instance.isMounted &&
70
+ !value.instance.isUnmounted &&
71
+ value.localFile &&
72
+ (!value.rootEl || value.isRootFragment)
73
+ ) {
74
+ if (!localComponents[value.localFile]) {
75
+ localComponents[value.localFile] = []
76
+ }
77
+ localComponents[value.localFile].push(enRichWithComponentName(value))
78
+ }
79
+ }
80
+ return localComponents
81
+ })
82
+
83
+ const appTree = computed(() => {
84
+ const appTreeNodes = Object.values(localComponentToElComputed.value).reduce(
85
+ (acc, localComponent) => [...acc, ...localComponent],
86
+ []
87
+ )
88
+ const appTreeNodesSorted = appTreeNodes.sort((a, b) =>
89
+ a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
90
+ )
91
+ return appTreeNodesSorted
92
+ })
93
+
94
+ winObj.pinegrow = {
95
+ elCache,
96
+ // // Uncomment these two to test locally
97
+ // elCacheErrHandlerFn,
98
+ // elUpdateHanderFn,
99
+ rootFragmentToPgIdComputed,
100
+ pgIdToElComputed,
101
+ localComponentToElComputed,
102
+ appTree,
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ // pgId & key can be optional
109
+ const pgUpdateElCache = (hook, pgId, rootEl, key, localFile) => async vnode => {
110
+ if (!vnode) return
111
+ if (window?.process?.client && process?.client !== true) return
112
+ if (!window.pinegrow) initCache()
113
+
114
+ let el = vnode.el
115
+ const instance = vnode.component || vnode.ctx || el.__vueParentComponent
116
+
117
+ try {
118
+ if ((key !== null && key !== undefined) || (vnode.key !== null && vnode.key !== undefined)) {
119
+ key = key || vnode.key
120
+ }
121
+ localFile = localFile || vnode.type.__file
122
+
123
+ let isRootFragment = false
124
+ let isFragment = el.nodeType !== 1
125
+ let firstEl,
126
+ lastEl,
127
+ isIsland = false
128
+
129
+ // May be an iles Island that wraps components with client directives
130
+ if (localFile) {
131
+ if (localFile.includes('node_modules/iles') && localFile.includes('Island.vue')) {
132
+ // Retain localFiles of iles island to apply to child elements
133
+ isIsland = true
134
+ }
135
+
136
+ if (localFile.includes('node_modules')) {
137
+ // Ignore SFCs from node_modules
138
+ localFile = null
139
+ }
140
+ }
141
+
142
+ // // Computed props anyway filters out unmounted ones, and we use the local components unmounted hooks to cleanup unmounted nodes. Using the unmounted hook seems to be out of sync when el is reused but instance is remounted.
143
+ // if (hook === 'unmounted') {
144
+ // if (pinegrow.elCache.has(el)) {
145
+ // pinegrow.elCache.delete(el)
146
+ // }
147
+ // for (let [key, value] of pinegrow.elCache.entries()) {
148
+ // if (value.rootEl === rootEl) {
149
+ // pinegrow.elCache.delete(key)
150
+ // }
151
+ // }
152
+ // return
153
+ // }
154
+
155
+ const prevElCache = pinegrow.elCache.get(el)
156
+ if (prevElCache) {
157
+ if (pgId && !prevElCache.pgIds.includes(pgId)) {
158
+ prevElCache.pgIds.push(pgId)
159
+ }
160
+ if (key !== null && key !== undefined) {
161
+ pinegrow.elCache.get(el).key = key
162
+ }
163
+ if (localFile) {
164
+ pinegrow.elCache.get(el).localFile = localFile
165
+ }
166
+ } else {
167
+ // Text/comment node
168
+ if (isFragment) {
169
+ if (!rootEl) {
170
+ // root Fragment
171
+ isRootFragment = true
172
+ }
173
+
174
+ function isFragmentEl(instance) {
175
+ // return appRecord.options.types.Fragment === instance.subTree?.type
176
+ return instance.subTree.el.nodeType !== 1
177
+ }
178
+
179
+ function getRootVNodesFromComponentInstance(instance) {
180
+ if (isFragmentEl(instance)) {
181
+ return getFragmentRootVNodes(instance.subTree)
182
+ }
183
+ if (!instance.subTree) return []
184
+ return [instance.subTree]
185
+ }
186
+
187
+ function getFragmentRootVNodes(vnode) {
188
+ if (!vnode.children) return []
189
+
190
+ const list = []
191
+
192
+ for (let i = 0, l = vnode.children.length; i < l; i++) {
193
+ const childVnode = vnode.children[i]
194
+ if (childVnode.component) {
195
+ list.push(...getRootVNodesFromComponentInstance(childVnode.component))
196
+ } else if (childVnode) {
197
+ list.push(childVnode)
198
+ }
199
+ }
200
+
201
+ return list
202
+ }
203
+
204
+ let childVNodes = getRootVNodesFromComponentInstance(instance)
205
+
206
+ if (!childVNodes.length) {
207
+ // For NuxtLayout, no childVNodes are returned, the subTree.children is in fact an object {ctx: {}, default: f}
208
+ if (el.nextElementSibling) {
209
+ const childEl = el.nextElementSibling
210
+ firstEl = lastEl = childEl
211
+ const childInstance = childEl.$ || childEl.__vueParentComponent
212
+ const childVNode = childInstance?.vnode // or subTree?
213
+ if (childVNode) {
214
+ childVNodes.push(childVNode)
215
+ }
216
+ }
217
+ }
218
+
219
+ if (childVNodes.length) {
220
+ // Filter out recursive vnodes text1 -> div, text1 (happens when text1 is the closest to a fragment with div & slot)
221
+ childVNodes = childVNodes.filter(childVNode => childVNode.el !== el)
222
+
223
+ if (childVNodes.length === 1) {
224
+ firstEl = lastEl = childVNodes[0].el
225
+ } else {
226
+ firstEl = childVNodes[0].el
227
+ lastEl = childVNodes[childVNodes.length - 1].el
228
+ }
229
+
230
+ if (firstEl && firstEl.nodeType !== 1) {
231
+ firstEl = firstEl.nextElementSibling
232
+ }
233
+ if (lastEl && lastEl.nodeType !== 1) {
234
+ lastEl = lastEl.nextElementSibling
235
+ }
236
+
237
+ childVNodes.forEach(childVNode => {
238
+ pgUpdateElCache(hook, pgId, isRootFragment ? el : rootEl, key)(childVNode)
239
+ })
240
+ }
241
+ }
242
+
243
+ pinegrow.elCache.set(el, {
244
+ el,
245
+ isRootFragment,
246
+ rootEl,
247
+ vnode,
248
+ instance,
249
+ isFragment,
250
+ firstEl,
251
+ lastEl,
252
+ pgIds: pgId ? [pgId] : [],
253
+ key,
254
+ localFile,
255
+ isIsland,
256
+ })
257
+ }
258
+
259
+ if (pinegrow.elUpdateHanderFn) {
260
+ pinegrow.elUpdateHanderFn(el)
261
+ }
262
+ } catch (err) {
263
+ if (pinegrow.elCacheErrHandlerFn) {
264
+ pinegrow.elCacheErrHandlerFn(vnode, hook, rootEl, pgId, key, el, instance, err.message)
265
+ }
266
+ }
267
+ }
268
+
269
+ const elUpdateHanderFn = el => {
270
+ // if (pinegrow.elCache.has(el)) {
271
+ // const { pgId } = pinegrow.elCache.get(el)
272
+ // if (pgId) {
273
+ // // console.log(`Reselect ${pgId}`)
274
+ // }
275
+ // }
276
+ }
277
+
278
+ const elCacheErrHandlerFn = () => {
279
+ if (message) {
280
+ console.log(message)
281
+ }
282
+ }
283
+
284
+ const cleanupCache = () => {
285
+ // for (let [key, value] of pinegrow.elCache.entries()) {
286
+ // if (value.isFragment && !value.firstEl) {
287
+ // console.log(value)
288
+ // }
289
+ // }
290
+ for (let [key, value] of pinegrow.elCache.entries()) {
291
+ if (value.instance.isUnmounted) {
292
+ pinegrow.elCache.delete(key)
293
+ // console.log(value)
294
+ }
295
+ }
296
+ }
297
+
298
+ // Local Component
299
+ const rootVNode = ref(null)
300
+
301
+ const mountLocalComponent = () => {
302
+ const instance = getCurrentInstance()
303
+ const vnode = instance?.vnode
304
+ const el = vnode?.el
305
+ const localFile = instance.type.__file && !instance.type.__file.includes('node_modules') && instance.type.__file
306
+
307
+ if (instance && vnode && el) {
308
+ rootVNode.value = vnode
309
+ pgUpdateElCache('mounted', null, null, null, localFile)(vnode)
310
+ }
311
+ }
312
+
313
+ const unmountLocalComponent = () => {
314
+ if (rootVNode.value) {
315
+ pgUpdateElCache('unmounted')(rootVNode.value)
316
+ }
317
+ cleanupCache()
318
+ }
319
+
320
+ onBeforeMount(() => initCache())
321
+ onMounted(() => {
322
+ mountLocalComponent()
323
+ })
324
+ onBeforeUnmount(() => unmountLocalComponent())
325
+
326
+ return { pgUpdateElCache }
327
+ }
328
+
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@pinegrow/vite-plugin",
3
- "version": "3.0.0-beta.5",
3
+ "version": "3.0.0-beta.50",
4
4
  "description": "Pinegrow Vite Plugin",
5
5
  "type": "module",
6
6
  "files": [
7
- "dist"
7
+ "dist",
8
+ "./types.d.ts"
8
9
  ],
9
10
  "main": "./dist/index.cjs",
10
11
  "module": "./dist/index.cjs",
12
+ "types": "./types.d.ts",
11
13
  "exports": {
12
14
  ".": {
13
15
  "import": "./dist/index.cjs",
@@ -16,6 +18,9 @@
16
18
  "./dev": {
17
19
  "import": "./src/index.js",
18
20
  "require": "./src/index.js"
21
+ },
22
+ "./vue": {
23
+ "import": "./dist/vue-plugin.js"
19
24
  }
20
25
  },
21
26
  "keywords": [
@@ -33,7 +38,8 @@
33
38
  "increment-beta-version": "npm version prerelease --preid=beta"
34
39
  },
35
40
  "dependencies": {
36
- "node-html-parser": "^5.2.0",
37
- "@pinegrow/tailwind-plugin": "latest"
41
+ "@vue/compiler-sfc": "^3.2.45",
42
+ "magic-string": "^0.27.0",
43
+ "node-html-parser": "^6.1.5"
38
44
  }
39
45
  }
package/types.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ declare module '@pinegrow/vite-plugin'
2
+
3
+ // export interface liveDesigner {
4
+ // repoRoot?: string;
5
+ // configPath?: string;
6
+ // plugins?: string[];
7
+ // devtoolsKey?: string;
8
+ // vscodeTunnelUrl?: string
9
+ // customTypes?: {
10
+ // default?: {};
11
+ // };
12
+ // };
13
+