threlte-minify 0.0.1
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/LICENSE +21 -0
- package/README.md +81 -0
- package/package.json +62 -0
- package/plugin/__tests__/compile.spec.ts +92 -0
- package/plugin/__tests__/extractImports.spec.ts +66 -0
- package/plugin/__tests__/findImportAlias.spec.ts +150 -0
- package/plugin/__tests__/hasDotComponent.spec.ts +79 -0
- package/plugin/__tests__/index.spec.ts +100 -0
- package/plugin/__tests__/insertImports.spec.ts +62 -0
- package/plugin/__tests__/replaceDotComponents.spec.ts +241 -0
- package/plugin/__tests__/stripScriptTags.spec.ts +48 -0
- package/plugin/__tests__/viteBuild.spec.ts +133 -0
- package/plugin/compile.js +76 -0
- package/plugin/extractExistingImports.js +29 -0
- package/plugin/findImportAlias.js +26 -0
- package/plugin/hasDotComponent.js +53 -0
- package/plugin/index.d.ts +3 -0
- package/plugin/index.js +49 -0
- package/plugin/insertImports.js +29 -0
- package/plugin/replaceDotComponents.js +112 -0
- package/plugin/stripScriptTags.js +8 -0
package/plugin/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import MagicString from 'magic-string'
|
|
2
|
+
import { compile } from './compile.js'
|
|
3
|
+
import { hasDotComponent } from './hasDotComponent.js'
|
|
4
|
+
|
|
5
|
+
const tOverwrite = `
|
|
6
|
+
export { default as T } from './T.svelte'
|
|
7
|
+
|
|
8
|
+
export const extend = () => {
|
|
9
|
+
throw new Error('Threlte Minify is not compatible with the Threlte extend() function.')
|
|
10
|
+
}`
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @returns {import('vite').PluginOption}
|
|
15
|
+
*/
|
|
16
|
+
export const threlteMinify = () => {
|
|
17
|
+
return {
|
|
18
|
+
name: 'threlte-minify',
|
|
19
|
+
|
|
20
|
+
enforce: 'pre',
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param {string} src
|
|
25
|
+
* @param {string} id
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
async transform(src, id) {
|
|
29
|
+
if (id.endsWith('.svelte') && hasDotComponent(src)) {
|
|
30
|
+
const { code, map } = await compile(src, id)
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
code,
|
|
34
|
+
map: map?.toString(),
|
|
35
|
+
}
|
|
36
|
+
} else if (id.includes('@threlte/core') && id.endsWith('/T.js')) {
|
|
37
|
+
const str = new MagicString(src, { filename: id })
|
|
38
|
+
str.overwrite(0, src.length, tOverwrite)
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
code: str.toString(),
|
|
42
|
+
map: str.generateMap(),
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return Promise.resolve()
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import MagicString from 'magic-string'
|
|
2
|
+
import { extractExistingImports } from './extractExistingImports.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {Set<string>} imports
|
|
7
|
+
* @param {string} content
|
|
8
|
+
* @param {string=} filename
|
|
9
|
+
* @returns {{ code: string; map: import('magic-string').SourceMap }}
|
|
10
|
+
*/
|
|
11
|
+
export const insertImports = (imports, content, filename) => {
|
|
12
|
+
const str = new MagicString(content, { filename })
|
|
13
|
+
const existingImports = extractExistingImports(content, 'three')
|
|
14
|
+
const filteredImports = [...imports]
|
|
15
|
+
.filter((item) => {
|
|
16
|
+
if (existingImports.includes(item)) return false
|
|
17
|
+
return true
|
|
18
|
+
})
|
|
19
|
+
.join(', ')
|
|
20
|
+
|
|
21
|
+
if (filteredImports.length > 0) {
|
|
22
|
+
str.prepend(`\nimport { ${filteredImports} } from 'three'\n`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
code: str.toString(),
|
|
27
|
+
map: str.generateMap(),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import MagicString from 'magic-string'
|
|
2
|
+
import { findImportAlias } from './findImportAlias.js'
|
|
3
|
+
import { parse } from 'svelte/compiler'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {Set<string>} imports A list of imports from "THREE"
|
|
8
|
+
* @param {string} content The stringified component
|
|
9
|
+
* @param {string=} filename The component filename
|
|
10
|
+
* @returns {{ code: string, map: import('magic-string').SourceMap }}
|
|
11
|
+
*/
|
|
12
|
+
export const replaceDotComponents = (imports, content, filename) => {
|
|
13
|
+
const alias = findImportAlias(content, 'T')
|
|
14
|
+
const str = new MagicString(content, { filename })
|
|
15
|
+
|
|
16
|
+
if (!alias) {
|
|
17
|
+
return {
|
|
18
|
+
code: str.toString(),
|
|
19
|
+
map: str.generateMap(),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ast = parse(content)
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* @param {string} identifier
|
|
28
|
+
* @returns {boolean}
|
|
29
|
+
*/
|
|
30
|
+
const hasIdentifier = (identifier) => {
|
|
31
|
+
const escapedIdentifier = identifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
32
|
+
return new RegExp(`(?<![\\w$])${escapedIdentifier}(?![\\w$])`).test(content)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @param {string} componentName
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
const getTaggedComponentName = (componentName) => {
|
|
41
|
+
for (const item of imports) {
|
|
42
|
+
const [imported, localName] = item.split(/\s+as\s+/)
|
|
43
|
+
if (imported === componentName && localName) {
|
|
44
|
+
return localName
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let suffix = 0
|
|
49
|
+
let taggedComponentName = `THRELTE_MINIFY__${componentName}`
|
|
50
|
+
|
|
51
|
+
while (
|
|
52
|
+
hasIdentifier(taggedComponentName) ||
|
|
53
|
+
[...imports].some((item) => {
|
|
54
|
+
const [, localName] = item.split(/\s+as\s+/)
|
|
55
|
+
return localName === taggedComponentName
|
|
56
|
+
})
|
|
57
|
+
) {
|
|
58
|
+
suffix += 1
|
|
59
|
+
taggedComponentName = `THRELTE_MINIFY__${componentName}_${suffix}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
imports.add(`${componentName} as ${taggedComponentName}`)
|
|
63
|
+
return taggedComponentName
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
* @param {unknown} node
|
|
69
|
+
* @returns {void}
|
|
70
|
+
*/
|
|
71
|
+
const visit = (node) => {
|
|
72
|
+
if (!node || typeof node !== 'object') return
|
|
73
|
+
|
|
74
|
+
if (Array.isArray(node)) {
|
|
75
|
+
for (const child of node) {
|
|
76
|
+
visit(child)
|
|
77
|
+
}
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (node.type === 'InlineComponent' && node.name.startsWith(`${alias}.`)) {
|
|
82
|
+
const componentName = node.name.slice(alias.length + 1)
|
|
83
|
+
const taggedComponentName = getTaggedComponentName(componentName)
|
|
84
|
+
const openTagNameStart = node.start + 1
|
|
85
|
+
const openTagNameEnd = openTagNameStart + node.name.length
|
|
86
|
+
|
|
87
|
+
str.overwrite(openTagNameStart, openTagNameEnd, `${alias} is={${taggedComponentName}}`)
|
|
88
|
+
|
|
89
|
+
const closeTag = `</${node.name}`
|
|
90
|
+
const closeTagStart = content.lastIndexOf(closeTag, node.end)
|
|
91
|
+
|
|
92
|
+
if (closeTagStart > node.start) {
|
|
93
|
+
const closeTagNameStart = closeTagStart + 2
|
|
94
|
+
const closeTagNameEnd = closeTagNameStart + node.name.length
|
|
95
|
+
str.overwrite(closeTagNameStart, closeTagNameEnd, alias)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (const value of Object.values(node)) {
|
|
100
|
+
if (value && typeof value === 'object') {
|
|
101
|
+
visit(value)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
visit(ast.html)
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
code: str.toString(),
|
|
110
|
+
map: str.generateMap(),
|
|
111
|
+
}
|
|
112
|
+
}
|