xpine 0.0.4 → 0.0.6
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/dist/index.js +658 -0
- package/dist/src/build/dev-server.js +10 -0
- package/dist/src/build/spa.js +152 -0
- package/dist/src/scripts/xpine-build.js +420 -0
- package/dist/src/scripts/xpine-dev.js +481 -0
- package/dist/src/static/dev-server.js +9 -0
- package/{src/static/spa.mjs → dist/src/static/spa.js} +34 -58
- package/package.json +1 -1
- package/src/auth.ts +0 -40
- package/src/build/typescript-builder.ts +0 -180
- package/src/express.ts +0 -120
- package/src/runDevServer.ts +0 -64
- package/src/scripts/build-module.ts +0 -36
- package/src/scripts/build.ts +0 -274
- package/src/scripts/xpine-build.ts +0 -5
- package/src/scripts/xpine-dev.ts +0 -5
- package/src/static/dev-server.mjs +0 -9
- package/src/util/env.ts +0 -7
- package/src/util/get-config.ts +0 -65
- package/src/util/html.ts +0 -32
- package/src/util/require.ts +0 -5
package/src/scripts/build.ts
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import { build } from 'esbuild';
|
|
4
|
-
import builtinModules from 'builtin-modules';
|
|
5
|
-
import ts from 'typescript';
|
|
6
|
-
import {
|
|
7
|
-
convertEntryPointsToSingleFile,
|
|
8
|
-
findDataAttributesAndFunctions,
|
|
9
|
-
removeClientScriptInTSXFile
|
|
10
|
-
} from '../build/typescript-builder';
|
|
11
|
-
import { globSync } from 'glob';
|
|
12
|
-
import postcss from 'postcss';
|
|
13
|
-
// @ts-ignore
|
|
14
|
-
import tailwindPostcss from '@tailwindcss/postcss';
|
|
15
|
-
import { config } from '../util/get-config';
|
|
16
|
-
|
|
17
|
-
// Extensions to look for in the bundle
|
|
18
|
-
const extensions = ['.ts', '.tsx'];
|
|
19
|
-
const packageJson = JSON.parse(fs.readFileSync(config.packageJsonPath, 'utf-8'));
|
|
20
|
-
const allPackages = Object.keys(packageJson.devDependencies).concat(Object.keys(packageJson.dependencies));
|
|
21
|
-
const allPackagesIncludingNode = allPackages.concat(builtinModules);
|
|
22
|
-
|
|
23
|
-
export async function buildApp(isDev = false) {
|
|
24
|
-
try {
|
|
25
|
-
const srcDirFiles = globSync(config.srcDir + '/**/*.{js,ts,tsx,jsx}');
|
|
26
|
-
const { componentData, dataFiles, } = await buildAppFiles(srcDirFiles, isDev);
|
|
27
|
-
const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
|
|
28
|
-
await buildClientSideFiles([alpineDataFile], isDev);
|
|
29
|
-
fs.removeSync(config.distTempFolder);
|
|
30
|
-
await buildCSS();
|
|
31
|
-
await buildPublicFolderSymlinks();
|
|
32
|
-
} catch (err) {
|
|
33
|
-
console.error('Build failed');
|
|
34
|
-
console.error(err);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function buildAppFiles(files: string[], isDev?: boolean) {
|
|
39
|
-
const componentData = [];
|
|
40
|
-
const dataFiles = [];
|
|
41
|
-
// Filter out client side files and files that aren't of the allowed extensions
|
|
42
|
-
const backendFiles = files
|
|
43
|
-
.filter((file) => extensions.find(ext => file.endsWith(ext)))
|
|
44
|
-
.filter((file) => !file.startsWith(config.publicDir));
|
|
45
|
-
fs.ensureDirSync(config.distDir);
|
|
46
|
-
// Build backend/SSR TSX modules
|
|
47
|
-
await build({
|
|
48
|
-
entryPoints: backendFiles,
|
|
49
|
-
format: 'esm',
|
|
50
|
-
platform: 'node',
|
|
51
|
-
outdir: config.distDir,
|
|
52
|
-
bundle: true,
|
|
53
|
-
sourcemap: isDev ? 'inline' : false,
|
|
54
|
-
external: allPackages,
|
|
55
|
-
jsx: 'transform',
|
|
56
|
-
minify: !isDev,
|
|
57
|
-
plugins: [
|
|
58
|
-
{
|
|
59
|
-
name: 'add-dot-js',
|
|
60
|
-
setup(build) {
|
|
61
|
-
build.onResolve({ filter: /.*/, }, args => {
|
|
62
|
-
const hasAtSign = args.path.startsWith('@');
|
|
63
|
-
const isPackage = hasAtSign ?
|
|
64
|
-
allPackagesIncludingNode.includes(args.path) :
|
|
65
|
-
allPackagesIncludingNode.includes(args.path.split('/').shift());
|
|
66
|
-
if (args.importer && !isPackage) {
|
|
67
|
-
// If we're doing an index import we need /index.js
|
|
68
|
-
const calculatedDir = path.join(args.resolveDir, args.path);
|
|
69
|
-
let existsAsFile = false;
|
|
70
|
-
for (const extension of extensions) {
|
|
71
|
-
const asFile = calculatedDir + extension;
|
|
72
|
-
const exists = fs.existsSync(asFile);
|
|
73
|
-
if (exists) existsAsFile = true;
|
|
74
|
-
}
|
|
75
|
-
let outputPath = args.path + (existsAsFile ? '' : '/index') + '.js';
|
|
76
|
-
outputPath = args.path.endsWith('.js') || args.path.endsWith('.mjs') ? args.path : outputPath;
|
|
77
|
-
return { path: outputPath, external: true, };
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
name: 'insert-html-banner-and-remove-client-scripts',
|
|
84
|
-
setup(build) {
|
|
85
|
-
build.onLoad({ filter: /.tsx/, }, args => {
|
|
86
|
-
const cleanedContent = removeClientScriptInTSXFile(args.path);
|
|
87
|
-
const htmlImportStart = 'import { html } from \'xpine\';\n';
|
|
88
|
-
const newContent = `${htmlImportStart}${cleanedContent.content}`;
|
|
89
|
-
componentData.push({
|
|
90
|
-
...args,
|
|
91
|
-
contents: `${htmlImportStart}${cleanedContent.fullContent}`,
|
|
92
|
-
clientContent: cleanedContent.clientContent,
|
|
93
|
-
});
|
|
94
|
-
return {
|
|
95
|
-
contents: newContent,
|
|
96
|
-
loader: 'tsx',
|
|
97
|
-
};
|
|
98
|
-
});
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name: 'get-data-files',
|
|
103
|
-
setup(build) {
|
|
104
|
-
build.onLoad({ filter: /\.data\.(js|mjs|ts)$/, }, args => {
|
|
105
|
-
const contents = fs.readFileSync(args.path, 'utf-8');
|
|
106
|
-
dataFiles.push({
|
|
107
|
-
...args,
|
|
108
|
-
contents,
|
|
109
|
-
});
|
|
110
|
-
return {
|
|
111
|
-
contents,
|
|
112
|
-
loader: 'ts',
|
|
113
|
-
};
|
|
114
|
-
});
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
],
|
|
118
|
-
});
|
|
119
|
-
await logSize(config.distDir, 'app');
|
|
120
|
-
return {
|
|
121
|
-
componentData,
|
|
122
|
-
dataFiles,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Build client side files
|
|
127
|
-
async function buildClientSideFiles(alpineDataFiles: string[] = [], isDev?: boolean) {
|
|
128
|
-
// Write the temp file to use
|
|
129
|
-
const tempFilePath = path.join(config.distTempFolder, './app.ts');
|
|
130
|
-
fs.ensureFileSync(tempFilePath);
|
|
131
|
-
// Get all ts/js files in public folder but ignore the pages scripts
|
|
132
|
-
const pagesScriptsGlob = config.publicDir + '/scripts/pages/**/*.{js,ts}';
|
|
133
|
-
const clientFiles = globSync(
|
|
134
|
-
config.publicDir + '/**/*.{js,ts}',
|
|
135
|
-
{
|
|
136
|
-
ignore: pagesScriptsGlob,
|
|
137
|
-
}
|
|
138
|
-
);
|
|
139
|
-
// Filter out all public/pages files
|
|
140
|
-
convertEntryPointsToSingleFile(alpineDataFiles.concat(clientFiles), tempFilePath);
|
|
141
|
-
// Write dev server code to the temp file path
|
|
142
|
-
if (isDev) writeDevServerClientSideCode(tempFilePath);
|
|
143
|
-
// Write spa functionality to the temp file path
|
|
144
|
-
writeSpaClientSideCode(tempFilePath);
|
|
145
|
-
await build({
|
|
146
|
-
entryPoints: [tempFilePath],
|
|
147
|
-
bundle: true,
|
|
148
|
-
outdir: config.distPublicScriptsDir,
|
|
149
|
-
minify: !isDev,
|
|
150
|
-
sourcemap: isDev ? 'inline' : false,
|
|
151
|
-
});
|
|
152
|
-
// Build pages files scripts
|
|
153
|
-
const pagesFiles = globSync(pagesScriptsGlob);
|
|
154
|
-
await build({
|
|
155
|
-
entryPoints: pagesFiles || [],
|
|
156
|
-
bundle: true,
|
|
157
|
-
outdir: config.distPublicScriptsDir + '/pages',
|
|
158
|
-
minify: !isDev,
|
|
159
|
-
sourcemap: isDev ? 'inline' : false,
|
|
160
|
-
});
|
|
161
|
-
await logSize(config.distPublicDir, 'client');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function writeDevServerClientSideCode(tempFilePath: string) {
|
|
165
|
-
const devServerPath = path.join(import.meta.dirname, '../static/dev-server.js');
|
|
166
|
-
const content = fs.readFileSync(devServerPath, 'utf-8');
|
|
167
|
-
fs.appendFileSync(tempFilePath, `\n` + content);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function writeSpaClientSideCode(tempFilePath: string) {
|
|
171
|
-
const spaPath = path.join(import.meta.dirname, '../static/spa.js');
|
|
172
|
-
const content = fs.readFileSync(spaPath, 'utf-8');
|
|
173
|
-
fs.appendFileSync(tempFilePath, `\n` + content);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async function buildAlpineDataFile(componentData: any[], dataFiles: any[]) {
|
|
177
|
-
const output = {
|
|
178
|
-
imports: [
|
|
179
|
-
'import Alpine from \'alpinejs\';'
|
|
180
|
-
],
|
|
181
|
-
code: [],
|
|
182
|
-
end: [
|
|
183
|
-
'window.Alpine = Alpine;'
|
|
184
|
-
],
|
|
185
|
-
};
|
|
186
|
-
const dataFunctionResults = {
|
|
187
|
-
foundDataAttributes: [],
|
|
188
|
-
foundFunctions: [],
|
|
189
|
-
foundImports: [],
|
|
190
|
-
};
|
|
191
|
-
const componentsAndDataFiles = componentData.concat(dataFiles);
|
|
192
|
-
for (const component of componentsAndDataFiles) {
|
|
193
|
-
// Single source file
|
|
194
|
-
const sourceFile = ts.createSourceFile(
|
|
195
|
-
component.path,
|
|
196
|
-
component.contents,
|
|
197
|
-
ts.ScriptTarget.Latest
|
|
198
|
-
);
|
|
199
|
-
const dataFunctionResult = findDataAttributesAndFunctions(sourceFile, sourceFile);
|
|
200
|
-
dataFunctionResults.foundDataAttributes.push(...dataFunctionResult.foundDataAttributes);
|
|
201
|
-
const foundFunctionsWithPath = dataFunctionResult.foundFunctions.map(item => {
|
|
202
|
-
return {
|
|
203
|
-
...item,
|
|
204
|
-
path: component.path,
|
|
205
|
-
content: component.clientContent,
|
|
206
|
-
};
|
|
207
|
-
});
|
|
208
|
-
dataFunctionResults.foundFunctions.push(...foundFunctionsWithPath);
|
|
209
|
-
}
|
|
210
|
-
const validDataFunctions = dataFunctionResults.foundFunctions.filter(item => {
|
|
211
|
-
return dataFunctionResults.foundDataAttributes.includes(item.name) && item.content;
|
|
212
|
-
});
|
|
213
|
-
for (const dataFunction of validDataFunctions) {
|
|
214
|
-
if (!dataFunction.hasExport) continue;
|
|
215
|
-
output.code.push(dataFunction.content);
|
|
216
|
-
output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
|
|
217
|
-
}
|
|
218
|
-
const result = output.imports.join('\n') + '\n' + output.code.join('\n') + '\n' + output.end.join('\n');
|
|
219
|
-
fs.ensureFileSync(config.alpineDataPath);
|
|
220
|
-
fs.writeFileSync(config.alpineDataPath, result);
|
|
221
|
-
return config.alpineDataPath;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export async function buildCSS() {
|
|
225
|
-
const cssFiles = globSync(config.srcDir + '/**/*.css');
|
|
226
|
-
for (const file of cssFiles) {
|
|
227
|
-
const fileContents = fs.readFileSync(file, 'utf-8');
|
|
228
|
-
const result = await postcss([tailwindPostcss()]).process(fileContents, { from: file, });
|
|
229
|
-
// Write to dist folder
|
|
230
|
-
const newPath = file.replace(config.srcDir, config.distDir);
|
|
231
|
-
fs.ensureFileSync(newPath);
|
|
232
|
-
fs.writeFileSync(newPath, result.css);
|
|
233
|
-
}
|
|
234
|
-
logSize(config.distPublicDir, 'css');
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// We need to symlink the non CSS or JS files from the src/public folder into the dist folder
|
|
238
|
-
export async function buildPublicFolderSymlinks() {
|
|
239
|
-
const files = globSync(config.publicDir + '/**/*.*', {
|
|
240
|
-
ignore: '/**/*.{css,js,ts,tsx,jsx}',
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// Create symlinks in dist directory
|
|
244
|
-
for (const file of files) {
|
|
245
|
-
try {
|
|
246
|
-
const newPath = file.replace(config.srcDir, config.distDir);
|
|
247
|
-
const splitNewPath = newPath.split('/');
|
|
248
|
-
splitNewPath.pop();
|
|
249
|
-
const newDir = splitNewPath.join('/');
|
|
250
|
-
fs.ensureDirSync(newDir);
|
|
251
|
-
fs.symlinkSync(file, newPath);
|
|
252
|
-
} catch { }
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
type FileItem = {
|
|
257
|
-
file: string;
|
|
258
|
-
size: number;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export async function logSize(pathName: string, type: 'app' | 'client' | 'css', validExtensions = ['.js', '.css']) {
|
|
262
|
-
const files = globSync(pathName + '/**/*' + (type === 'css' ? '.css' : ''));
|
|
263
|
-
const fileSizes = files.map((file) => {
|
|
264
|
-
if (!validExtensions.find(ext => file.endsWith(ext))) return false;
|
|
265
|
-
return {
|
|
266
|
-
file,
|
|
267
|
-
size: (fs.statSync(file).size) / (1024 * 1000),
|
|
268
|
-
};
|
|
269
|
-
}).filter(Boolean);
|
|
270
|
-
const totalSize = fileSizes.reduce((total, current: FileItem) => {
|
|
271
|
-
return current.size + total;
|
|
272
|
-
}, 0);
|
|
273
|
-
console.info(`[${totalSize.toFixed(3)} MB] Built ${type}`);
|
|
274
|
-
}
|
package/src/scripts/xpine-dev.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
const socketProtocol = 'ws:';
|
|
2
|
-
const echoSocketUrl = socketProtocol + '//' + window.location.hostname + ':3001/dev-server/';
|
|
3
|
-
const socket = new WebSocket(echoSocketUrl);
|
|
4
|
-
|
|
5
|
-
socket.addEventListener('message', async (msg) => {
|
|
6
|
-
if (msg.data === 'refresh:client') {
|
|
7
|
-
window.location.reload();
|
|
8
|
-
}
|
|
9
|
-
});
|
package/src/util/env.ts
DELETED
package/src/util/get-config.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import require from './require';
|
|
3
|
-
import { XPineConfig } from '../../types';
|
|
4
|
-
|
|
5
|
-
const rootDir = process.cwd();
|
|
6
|
-
|
|
7
|
-
export function fromRoot(pathName?: string) {
|
|
8
|
-
if (!pathName) return rootDir;
|
|
9
|
-
return path.join(rootDir, pathName);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const userConfig = require(path.join(process.cwd(), './xpine.config.mjs')).default;
|
|
13
|
-
|
|
14
|
-
const configDefaults = {
|
|
15
|
-
rootDir: fromRoot(),
|
|
16
|
-
srcDir: fromRoot('./src'),
|
|
17
|
-
distDir: fromRoot('./dist'),
|
|
18
|
-
packageJsonPath: fromRoot('package.json'),
|
|
19
|
-
// We need to use getters here in the event someone wants to change folders, such as the dist folder
|
|
20
|
-
get distPublicDir() {
|
|
21
|
-
return path.join(this.distDir, './public');
|
|
22
|
-
},
|
|
23
|
-
get distPublicScriptsDir() {
|
|
24
|
-
return path.join(this.distPublicDir, './scripts');
|
|
25
|
-
},
|
|
26
|
-
get distTempFolder() {
|
|
27
|
-
return path.join(this.distDir, './temp');
|
|
28
|
-
},
|
|
29
|
-
get clientJSBundlePath() {
|
|
30
|
-
return path.join(this.distPublicScriptsDir, './app.js');
|
|
31
|
-
},
|
|
32
|
-
get alpineDataPath() {
|
|
33
|
-
return path.join(this.distTempFolder, './alpine-data.ts');
|
|
34
|
-
},
|
|
35
|
-
get serverDistDir() {
|
|
36
|
-
return path.join(this.distDir, './server');
|
|
37
|
-
},
|
|
38
|
-
get serverDistAppPath() {
|
|
39
|
-
return path.join(this.serverDistDir, './app.js');
|
|
40
|
-
},
|
|
41
|
-
// Important dirs/paths
|
|
42
|
-
get pagesDir() {
|
|
43
|
-
return path.join(this.srcDir, './pages');
|
|
44
|
-
},
|
|
45
|
-
get publicDir() {
|
|
46
|
-
return path.join(this.srcDir, './public');
|
|
47
|
-
},
|
|
48
|
-
get serverDir() {
|
|
49
|
-
return path.join(this.srcDir, './server');
|
|
50
|
-
},
|
|
51
|
-
get runDir() {
|
|
52
|
-
return path.join(this.serverDir, './run');
|
|
53
|
-
},
|
|
54
|
-
get serverAppPath() {
|
|
55
|
-
return path.join(this.serverDir, './app.ts');
|
|
56
|
-
},
|
|
57
|
-
get globalCSSFile() {
|
|
58
|
-
return path.join(this.publicDir, './styles/global.css');
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export const config: XPineConfig = {
|
|
63
|
-
...configDefaults,
|
|
64
|
-
...userConfig,
|
|
65
|
-
};
|
package/src/util/html.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export class html {
|
|
2
|
-
|
|
3
|
-
static attributeObjectToString(props) {
|
|
4
|
-
if (!props) return '';
|
|
5
|
-
return Object.entries(props)
|
|
6
|
-
.filter(([, value]) => value !== null && value !== undefined)
|
|
7
|
-
.map(([key, value], index) => {
|
|
8
|
-
const start = index === 0 ? ' ' : '';
|
|
9
|
-
return `${start}${key}="${value}"`;
|
|
10
|
-
})
|
|
11
|
-
.join(' ');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
static async fragment(props) {
|
|
15
|
-
const childrenResult = await Promise.all(props.children.flat());
|
|
16
|
-
return childrenResult.filter(Boolean).join('');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
static async createElement(type, props, ...children) {
|
|
20
|
-
const childrenResult = await Promise.all(children.flat());
|
|
21
|
-
// Handle passing in another element
|
|
22
|
-
if (typeof type === 'function') {
|
|
23
|
-
const result = await type({ ...props, children: childrenResult, });
|
|
24
|
-
return result;
|
|
25
|
-
}
|
|
26
|
-
return `<${type}${this.attributeObjectToString(props)}>${childrenResult.filter(Boolean).join('')}</${type}>`;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function JSXRuntime() {
|
|
31
|
-
return true;
|
|
32
|
-
}
|