xpine 0.0.5 → 0.0.7

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.
@@ -1,180 +0,0 @@
1
- import ts from 'typescript';
2
- import fs from 'fs-extra';
3
- import path from 'path';
4
-
5
- type ImportDeclaration = {
6
- node: ts.Node;
7
- importPath: string;
8
- }
9
-
10
- // node arg should initially be the source node
11
- export function getImportDeclarationNodes(node: ts.Node, sourceFile: ts.SourceFile, importDeclarations: ImportDeclaration[] = []) {
12
- if (node.kind === ts.SyntaxKind.ImportDeclaration) {
13
- let importPath = null;
14
- node.forEachChild(child => {
15
- if (child.kind === ts.SyntaxKind.StringLiteral) {
16
- importPath = child.getText(sourceFile).replace(/[\"\']/g, '');
17
- }
18
- });
19
- importDeclarations.push({
20
- node,
21
- importPath,
22
- });
23
- }
24
- node.forEachChild(child => {
25
- getImportDeclarationNodes(child, sourceFile, importDeclarations);
26
- });
27
- return importDeclarations;
28
- }
29
-
30
- export function stripImportsNodesFromFile(importsToStrip: string[], content: string, importDeclarations: ImportDeclaration[]) {
31
- let outputContent = content;
32
- const filteredImports = importDeclarations.filter(item => importsToStrip.includes(item.importPath));
33
- for (const importItem of filteredImports) {
34
- outputContent = outputContent.slice(0, importItem.node.pos) + outputContent.slice(importItem.node.end);
35
- }
36
- return outputContent;
37
- }
38
-
39
- type FoundAlpineFunction = {
40
- name: string;
41
- isDefaultExport: boolean;
42
- hasExport: boolean;
43
- }
44
-
45
- export function findDataAttributesAndFunctions(
46
- node: ts.Node,
47
- sourceFile: ts.SourceFile,
48
- foundDataAttributes: string[] = [],
49
- foundFunctions: FoundAlpineFunction[] = []
50
- ) {
51
- if (node.kind === ts.SyntaxKind.JsxAttribute) {
52
- const attribute = getAttributeValuePair(node, sourceFile);
53
- if (attribute?.[0] === 'x-data' && attribute?.[1]) {
54
- // We found a data attribute,
55
- // so now we have to search throughout the file for a function declaration of the same name
56
- foundDataAttributes.push(attribute[1].replace(/[^a-zA-Z0-9]/g, ''));
57
- }
58
- }
59
- if (node.kind === ts.SyntaxKind.SourceFile) {
60
- node.forEachChild(child => {
61
- if ([ts.SyntaxKind.FunctionDeclaration, ts.SyntaxKind.VariableDeclaration].includes(child.kind)) {
62
- const functions = getFunctionDeclarationValue(child, sourceFile);
63
- foundFunctions.push(functions);
64
- }
65
- });
66
- }
67
-
68
- node.forEachChild(child => {
69
- findDataAttributesAndFunctions(child, sourceFile, foundDataAttributes, foundFunctions);
70
- });
71
- return {
72
- foundDataAttributes,
73
- foundFunctions,
74
- };
75
- }
76
-
77
- export function getAttributeValuePair(node: ts.Node, sourceFile: ts.SourceFile): string[] {
78
- const result = [];
79
- node.forEachChild(child => {
80
- result.push(child.getText(sourceFile));
81
- });
82
- return result;
83
- }
84
-
85
- export function getFunctionDeclarationValue(node: ts.Node, sourceFile: ts.SourceFile): FoundAlpineFunction {
86
- const result = {
87
- name: null,
88
- isDefaultExport: false,
89
- hasExport: false,
90
- };
91
- node.forEachChild(child => {
92
- if (child.kind === ts.SyntaxKind.ExportKeyword) {
93
- result.hasExport = true;
94
- }
95
- if (child.kind === ts.SyntaxKind.DefaultKeyword) {
96
- result.isDefaultExport = true;
97
- }
98
- if (child.kind === ts.SyntaxKind.Identifier) {
99
- result.name = child.getText(sourceFile);
100
- }
101
- });
102
- return result;
103
- }
104
-
105
- // Convert entry point files into one big bundle file
106
- export function convertEntryPointsToSingleFile(entryPoints: string[], tempWritePath: string) {
107
- fs.writeFileSync(
108
- tempWritePath,
109
- entryPoints
110
- .map(entry => `import "${entry}"`)
111
- .join(';\n')
112
- );
113
- }
114
-
115
- export function removeClientScriptInTSXFile(pathName: string) {
116
- const content = fs.readFileSync(pathName, 'utf-8');
117
- const source = ts.createSourceFile(
118
- pathName,
119
- content,
120
- ts.ScriptTarget.Latest
121
- );
122
- let toRemoveFrom: number;
123
- let clientDataStart: number;
124
- const clientImportsToHoist = [];
125
- const clientImportsToReplace = [];
126
- source.forEachChild((child) => {
127
- if (child.kind === ts.SyntaxKind.ExpressionStatement) {
128
- const text = child.getText(source);
129
- // Remove from here
130
- if (text.startsWith('<script')) {
131
- toRemoveFrom = child.pos;
132
- clientDataStart = child.end;
133
- }
134
- }
135
- // Hoist the client imports to above the <script /> tag
136
- if (child.kind === ts.SyntaxKind.ImportDeclaration && child.pos >= clientDataStart) {
137
- const text = child.getText(source);
138
- child.forEachChild(child => {
139
- if (child.kind === ts.SyntaxKind.StringLiteral) {
140
- // Keep track of client imports needed for path replacement to be absolute
141
- const text = child.getText(source);
142
- const importPath = text.replace(/[\"\']/g, '');
143
- const isRelativeImport = importPath.startsWith('.') || importPath.startsWith('/');
144
- if (!isRelativeImport) return;
145
- clientImportsToReplace.push({
146
- old: importPath,
147
- new: path.join(path.dirname(pathName), importPath),
148
- });
149
- }
150
- });
151
- clientImportsToHoist.push(text);
152
- }
153
- });
154
- let clientContent = !isNaN(clientDataStart) ? content.slice(clientDataStart) : '';
155
- for (const clientImport of clientImportsToReplace) {
156
- clientContent = clientContent.replace(clientImport.old, clientImport.new);
157
- }
158
- return {
159
- content: !isNaN(toRemoveFrom) ?
160
- clientImportsToHoist.join('\n') + content.slice(0, toRemoveFrom) :
161
- content,
162
- clientContent,
163
- fullContent: content,
164
- toRemoveFrom,
165
- clientDataStart,
166
- };
167
- }
168
-
169
- export function printRecursiveFrom(
170
- node: ts.Node, indentLevel: number, sourceFile: ts.SourceFile
171
- ) {
172
- const indentation = '-'.repeat(indentLevel);
173
- const syntaxKind = ts.SyntaxKind[node.kind];
174
- const nodeText = node.getText(sourceFile);
175
- console.log(`${indentation}${syntaxKind}: ${nodeText}`);
176
-
177
- node.forEachChild(child =>
178
- printRecursiveFrom(child, indentLevel + 1, sourceFile)
179
- );
180
- }
package/src/express.ts DELETED
@@ -1,120 +0,0 @@
1
- import express, { NextFunction, Express, Request, Response } from 'express';
2
- import { globSync } from 'glob';
3
- import { config } from './util/get-config';
4
- import { verifyUser } from './auth';
5
- import requestIP from 'request-ip';
6
- import { ServerRequest } from '../types';
7
-
8
- const doctypeHTML = '<!DOCTYPE html>';
9
-
10
- export async function createRouter() {
11
- const methods = ['get', 'post', 'put', 'patch', 'delete'];
12
- const router = express.Router();
13
- const routes = globSync(config.pagesDir + '/**/*.{tsx,ts}');
14
- const routeMap = routes.map(route => {
15
- return {
16
- route: route.split(config.pagesDir).pop().replace('.tsx', '').replace('.js', '').replace('.ts', '').replace('/index', '/'),
17
- path: route.replace(config.srcDir, config.distDir).replace('.tsx', '.js').replace('.ts', '.js'),
18
- originalRoute: route,
19
- };
20
- });
21
- const routeResults = [];
22
-
23
- for (const route of routeMap) {
24
- const isJSX = route.originalRoute.endsWith('.tsx') || route.originalRoute.endsWith('.jsx');
25
- // Import route
26
- const routeItem = process.env.NODE_ENV === 'development' ? null : (await import(route.path)).default;
27
- // Configure result,methods for the route
28
- const slugRoute = route.route.toLowerCase().replace(/[ ]/g, '');
29
- const foundMethod = methods.find(method => slugRoute.endsWith(`.${method}`));
30
- const isDynamicRoute = slugRoute.match(/\[(.*)\]/g);
31
- let formattedRouteItem = slugRoute;
32
- if (foundMethod) formattedRouteItem = formattedRouteItem.split('.').shift();
33
- // Handle dynamic routing
34
- if (isDynamicRoute) {
35
- const result = [...formattedRouteItem.matchAll(/(\[)(.*?)(\])/g)];
36
- for (const match of result) {
37
- formattedRouteItem = formattedRouteItem.replace(match[0], ':' + match[2]);
38
- }
39
- }
40
- // Push to the route results array
41
- routeResults.push({
42
- formattedRouteItem,
43
- foundMethod,
44
- route,
45
- });
46
- router[foundMethod || 'get'](formattedRouteItem, async (req: Request, res: Response) => {
47
- try {
48
- // Check if it's a string response from the routeItem or is a different response
49
- if (routeItem) {
50
- if (isJSX) {
51
- res.send(doctypeHTML + (await routeItem(req, res)));
52
- } else {
53
- await routeItem(req, res);
54
- }
55
- return;
56
- }
57
- const defaultRouteImport = (await import(route.path + `?cache=${Date.now()}`)).default;
58
- // Require every time only if in development mode
59
- if (isJSX) {
60
- res.send(doctypeHTML + (await defaultRouteImport(req, res)));
61
- } else {
62
- await defaultRouteImport(req, res);
63
- }
64
- } catch (err) {
65
- console.error(err);
66
- res.status(err?.status || 500).send(err?.message || 'Error');
67
- }
68
- });
69
- }
70
- return {
71
- router,
72
- routeResults,
73
- };
74
- }
75
-
76
- async function verifyUserMiddleware(req: ServerRequest, _res: Response, next: NextFunction) {
77
- // @ts-ignore
78
- const { usertoken, } = req.cookies;
79
- if (!usertoken) {
80
- req.user = null;
81
- }
82
- try {
83
- const { user, } = await verifyUser(usertoken);
84
- req.user = user;
85
- } catch (err) {
86
- req.user = null;
87
- }
88
- next();
89
- }
90
-
91
- export async function createXPineRouter(app: any, beforeErrorRoute?: (app: Express) => void) {
92
- app.use(express.static(config.distPublicDir));
93
- app.use(verifyUserMiddleware);
94
- app.use(requestIP.mw());
95
-
96
- const { router, routeResults, } = await createRouter();
97
- app.use(function replaceableRouter(req: Request, res: Response, next: NextFunction) {
98
- router(req, res, next);
99
- });
100
-
101
- const found404 = routeResults?.find(item => item?.formattedRouteItem === '/404');
102
- const import404 = process.env.NODE_ENV === 'development' ? null : (await import(found404.route.path)).default;
103
-
104
- if (beforeErrorRoute) beforeErrorRoute(app);
105
-
106
- // error handler
107
- app.use(async function (req: Request, res: Response) {
108
- // render the error page
109
- res.status(404);
110
-
111
- if (import404) {
112
- res.send(doctypeHTML + (await import404(req, res)));
113
- } else if (found404 && process.env.NODE_ENV === 'development') {
114
- const import404Item = (await import(found404.route.path + `?cache=${Date.now()}`)).default
115
- res.send(doctypeHTML + (await import404Item(req, res)));
116
- } else {
117
- res.send('Error');
118
- }
119
- });
120
- }
@@ -1,64 +0,0 @@
1
- import expressWs from 'express-ws';
2
- import http from 'http';
3
- import express from 'express';
4
- import EventEmitter from 'events';
5
- import chokidar from 'chokidar';
6
- import { buildApp } from './scripts/build';
7
- import path from 'path';
8
- import { config } from './util/get-config';
9
- import { setupEnv } from './util/env';
10
-
11
- setupEnv();
12
-
13
- export async function runDevServer() {
14
- process.env.NODE_ENV = 'development';
15
- const startServer = await import(config.serverDistAppPath + `?cache=${Date.now()}`);
16
-
17
- // Initial server set up
18
- await buildApp(true);
19
- let appServer = await startServer.default();
20
-
21
- // Watch files
22
- const watcher = chokidar.watch(config.srcDir, {
23
- ignoreInitial: true,
24
- // Ignore map and prisma files
25
- ignored: (pathName) => pathName.endsWith('.map') || pathName.startsWith(path.join(config.serverDir, './prisma')),
26
- });
27
- watcher.on('all', async (event, path) => {
28
- const shouldReloadServer = (path.startsWith(config.serverDir) && !path.startsWith(config.runDir)) ||
29
- ['add', 'unlink'].includes(event) && path.startsWith(config.pagesDir);
30
- if (shouldReloadServer) {
31
- // We modified files in the server, restart the server
32
- appServer.server.close();
33
- await buildApp(true);
34
- const startServer = await import(config.serverDistAppPath + `?cache=${Date.now()}`);
35
- appServer = await startServer.default();
36
- return;
37
- }
38
- await buildApp(true);
39
- refreshEmitter.emit('refresh');
40
- });
41
-
42
- // Create web socket sever
43
- const wsApp = express();
44
- const wsServer = http.createServer(wsApp);
45
- expressWs(wsApp, wsServer);
46
- class RefreshEmitter extends EventEmitter { };
47
- const refreshEmitter = new RefreshEmitter();
48
-
49
- // @ts-ignore
50
- wsApp.ws('/dev-server', function (ws) {
51
- refreshEmitter.removeAllListeners();
52
- refreshEmitter.on('refresh', () => {
53
- ws.send('refresh:client');
54
- });
55
- });
56
-
57
- const wsPort = 3001;
58
- wsServer.listen(wsPort);
59
- wsServer.on('listening', () => {
60
- console.info(`Dev server listening on port ${wsPort}`);
61
- });
62
- }
63
-
64
-
@@ -1,36 +0,0 @@
1
- import fs from 'fs-extra';
2
- import { build } from 'esbuild';
3
- import { config } from '../util/get-config';
4
- import path from 'path';
5
-
6
- // Extensions to look for in the bundle
7
- const packageJson = JSON.parse(fs.readFileSync(config.packageJsonPath, 'utf-8'));
8
- const allPackages = Object.keys(packageJson.devDependencies).concat(Object.keys(packageJson.dependencies));
9
- const dirname = import.meta.dirname;
10
-
11
- export async function buildXPine() {
12
- await build({
13
- entryPoints: [
14
- // The contents of XPine itself
15
- path.join(dirname, '../../index.ts'),
16
- // The script for xpine-build
17
- path.join(dirname, './xpine-build.ts'),
18
- // The script for xpine-dev
19
- path.join(dirname, './xpine-dev.ts'),
20
- // Static files
21
- path.join(dirname, '../static/dev-server.mjs'),
22
- path.join(dirname, '../static/spa.mjs'),
23
- ],
24
- format: 'esm',
25
- platform: 'node',
26
- outdir: path.join(dirname, '../../dist'),
27
- bundle: true,
28
- sourcemap: 'inline',
29
- external: allPackages,
30
- jsx: 'transform',
31
- minify: false,
32
- plugins: [],
33
- });
34
- }
35
-
36
- buildXPine();
@@ -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
- }
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { buildApp } from './build';
4
-
5
- buildApp();
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { runDevServer } from '../runDevServer';
4
-
5
- runDevServer();
@@ -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
- });