actionview-svelte-handler 0.2.0 → 0.4.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.
data/lib/ts/builder.ts ADDED
@@ -0,0 +1,174 @@
1
+ import { readable, Stores } from 'svelte/store'
2
+ import { importFromStringSync } from 'module-from-string'
3
+ import * as esbuild from 'esbuild'
4
+ import sveltePlugin from 'esbuild-svelte'
5
+ import { sveltePreprocess } from 'svelte-preprocess'
6
+ import type { Warning } from 'svelte/types/compiler/interfaces'
7
+ import * as recast from 'recast'
8
+
9
+ export interface BuildSuccess {
10
+ client: string
11
+ server: {
12
+ html: string
13
+ css: string
14
+ } | null
15
+ compiled: {
16
+ client: string
17
+ server: string | undefined
18
+ }
19
+ }
20
+
21
+ export interface BuildError {
22
+ error: any
23
+ }
24
+
25
+ export type BuildResult = BuildSuccess | BuildError
26
+
27
+ /**
28
+ * Builder is a class that builds, compiles and bundles Svelte components into a nice object for the template handler
29
+ */
30
+ class Builder {
31
+ path: string
32
+ props: Stores
33
+ locals: object
34
+ compiled: {
35
+ client: string | null
36
+ server: string | null
37
+ }
38
+
39
+ ssr: boolean
40
+ workingDir: string
41
+ preprocess: object
42
+
43
+ constructor (
44
+ path: string,
45
+ props: object,
46
+ locals: object,
47
+ client: string | null,
48
+ server: string | null,
49
+ ssr: boolean,
50
+ workingDir: string,
51
+ preprocess: object
52
+ ) {
53
+ this.path = path
54
+ this.props = readable(props)
55
+ this.locals = locals
56
+ this.compiled = {
57
+ client,
58
+ server
59
+ }
60
+ this.ssr = ssr
61
+ this.workingDir = workingDir
62
+ this.preprocess = preprocess
63
+ }
64
+
65
+ async bundle (generate: 'ssr' | 'dom', sveltePath = 'svelte'): Promise<string> {
66
+ const bundle = await esbuild.build({
67
+ entryPoints: [this.path],
68
+ mainFields: ['svelte', 'browser', 'module', 'main'],
69
+ conditions: ['svelte', 'browser'],
70
+ absWorkingDir: this.workingDir,
71
+ write: false,
72
+ outfile: 'component.js',
73
+ bundle: true,
74
+ format: 'esm',
75
+ metafile: true,
76
+ plugins: [
77
+ // @ts-expect-error
78
+ sveltePlugin({
79
+ compilerOptions: {
80
+ generate,
81
+ css: 'injected',
82
+ hydratable: true,
83
+ sveltePath
84
+ },
85
+ preprocess: sveltePreprocess(this.preprocess),
86
+ filterWarnings: (warning: Warning) => {
87
+ if (
88
+ warning.code === 'missing-declaration' &&
89
+ warning.message.includes("'props'")
90
+ ) {
91
+ return false
92
+ }
93
+ return true
94
+ }
95
+ })
96
+ ]
97
+ })
98
+
99
+ // @ts-expect-error
100
+ const throwables = [].concat(bundle.errors, bundle.warnings)
101
+
102
+ if (throwables.length > 0) {
103
+ throw throwables[0] // eslint-disable-line @typescript-eslint/no-throw-literal
104
+ }
105
+
106
+ return bundle.outputFiles[0].text
107
+ }
108
+
109
+ async client (): Promise<string> {
110
+ return (
111
+ this.compiled?.client || (this.standardizeClient(await this.bundle('dom', 'https://esm.sh/svelte'))) // eslint-disable-line
112
+ )
113
+ }
114
+
115
+ standardizeClient (code: string): string {
116
+ const ast = recast.parse(code)
117
+
118
+ let name: string | undefined
119
+
120
+ recast.visit(ast, {
121
+ visitExportNamedDeclaration: (path) => {
122
+ const stagingName: any = path.node?.specifiers?.[0].local?.name
123
+ name = typeof stagingName !== 'string' ? '' : stagingName
124
+ path.prune()
125
+ return false
126
+ }
127
+ })
128
+
129
+ recast.visit(ast, {
130
+ visitIdentifier: (path) => {
131
+ if (path.node.name === name) {
132
+ path.node.name = 'App'
133
+ }
134
+ return false
135
+ }
136
+ })
137
+
138
+ return recast.print(ast).code
139
+ }
140
+
141
+ async server (): Promise<{ output: string, html: string, css: string }> {
142
+ const output = this.compiled?.server || (await this.bundle('ssr')) // eslint-disable-line
143
+
144
+ const Component = importFromStringSync(output, {
145
+ globals: { props: this.props }
146
+ }).default
147
+
148
+ const { html, css } = await Component.render(this.locals)
149
+
150
+ return { output, html, css: css.code }
151
+ }
152
+
153
+ async build (): Promise<BuildResult> {
154
+ try {
155
+ const serv = this.ssr ? await this.server() : null
156
+ const cli = await this.client()
157
+
158
+ const comp = {
159
+ client: cli,
160
+ server: serv?.output
161
+ }
162
+
163
+ return {
164
+ client: cli,
165
+ server: serv,
166
+ compiled: comp
167
+ }
168
+ } catch (e) {
169
+ return { error: e }
170
+ }
171
+ }
172
+ }
173
+
174
+ export default Builder
@@ -0,0 +1,2 @@
1
+ > [!CAUTION]
2
+ > This folder is intended to be built from TypeScript files with `npm run build`
@@ -0,0 +1,42 @@
1
+ import { Stores } from 'svelte/store';
2
+ export interface BuildSuccess {
3
+ client: string;
4
+ server: {
5
+ html: string;
6
+ css: string;
7
+ } | null;
8
+ compiled: {
9
+ client: string;
10
+ server: string | undefined;
11
+ };
12
+ }
13
+ export interface BuildError {
14
+ error: any;
15
+ }
16
+ export type BuildResult = BuildSuccess | BuildError;
17
+ /**
18
+ * Builder is a class that builds, compiles and bundles Svelte components into a nice object for the template handler
19
+ */
20
+ declare class Builder {
21
+ path: string;
22
+ props: Stores;
23
+ locals: object;
24
+ compiled: {
25
+ client: string | null;
26
+ server: string | null;
27
+ };
28
+ ssr: boolean;
29
+ workingDir: string;
30
+ preprocess: object;
31
+ constructor(path: string, props: object, locals: object, client: string | null, server: string | null, ssr: boolean, workingDir: string, preprocess: object);
32
+ bundle(generate: 'ssr' | 'dom', sveltePath?: string): Promise<string>;
33
+ client(): Promise<string>;
34
+ standardizeClient(code: string): string;
35
+ server(): Promise<{
36
+ output: string;
37
+ html: string;
38
+ css: string;
39
+ }>;
40
+ build(): Promise<BuildResult>;
41
+ }
42
+ export default Builder;