juxscript 1.0.1 → 1.0.2

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/README.md CHANGED
@@ -21,7 +21,19 @@ Have you ever considered the energy requirements to ship chunks of HTML markup l
21
21
 
22
22
  ## GETTING STARTED
23
23
 
24
-
24
+ ```bash
25
+ # New project
26
+ mkdir my-project
27
+ cd my-project
28
+ npm init -y
29
+ npm install juxscript
30
+
31
+ # Initialize (creates jux/ directory)
32
+ npx jux init
33
+
34
+ # Builds jux-dist and serves index.jux
35
+ npx jux serve
36
+ ```
25
37
  > install
26
38
  `npm i juxscript`
27
39
 
package/bin/cli.js CHANGED
@@ -10,30 +10,36 @@ import { fileURLToPath } from 'url';
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
12
12
 
13
- // CLEAR PATH CONTRACT
13
+ // CLEAR PATH CONTRACT - CONVENTIONS
14
14
  const PATHS = {
15
15
  // Where jux package is installed (in node_modules/juxscript or local dev)
16
16
  packageRoot: path.resolve(__dirname, '..'),
17
17
 
18
- // Where the user's project is (where they run `npx jux`)
18
+ // Where the user's project root is (where they run `npx jux`)
19
19
  projectRoot: process.cwd(),
20
20
 
21
+ // Where user's .jux source files live (CONVENTION: ./jux/)
22
+ get juxSource() {
23
+ return path.join(this.projectRoot, 'jux');
24
+ },
25
+
21
26
  // Where jux lib files are (components, layouts, etc.)
22
27
  get juxLib() {
23
28
  return path.join(this.packageRoot, 'lib');
24
29
  },
25
30
 
26
- // Where user's dist output goes
27
- get projectDist() {
28
- return path.join(this.projectRoot, 'dist');
31
+ // Where frontend build output goes (CONVENTION: ./jux-dist/)
32
+ get frontendDist() {
33
+ return path.join(this.projectRoot, 'jux-dist');
29
34
  }
30
35
  };
31
36
 
32
37
  console.log('šŸ“ JUX Paths:');
33
- console.log(` Package: ${PATHS.packageRoot}`);
34
- console.log(` Project: ${PATHS.projectRoot}`);
35
- console.log(` Lib: ${PATHS.juxLib}`);
36
- console.log(` Dist: ${PATHS.projectDist}\n`);
38
+ console.log(` Package: ${PATHS.packageRoot}`);
39
+ console.log(` Project: ${PATHS.projectRoot}`);
40
+ console.log(` Source: ${PATHS.juxSource}`);
41
+ console.log(` Output: ${PATHS.frontendDist}`);
42
+ console.log(` Lib: ${PATHS.juxLib}\n`);
37
43
 
38
44
  const command = process.argv[2];
39
45
 
@@ -47,7 +53,7 @@ function findJuxFiles(dir, fileList = []) {
47
53
  const stat = fs.statSync(filePath);
48
54
 
49
55
  if (stat.isDirectory()) {
50
- if (file !== 'node_modules' && file !== 'dist' && file !== '.git') {
56
+ if (file !== 'node_modules' && file !== 'jux-dist' && file !== '.git' && file !== 'server') {
51
57
  findJuxFiles(filePath, fileList);
52
58
  }
53
59
  } else if (file.endsWith('.jux')) {
@@ -75,14 +81,21 @@ async function loadConfig() {
75
81
  }
76
82
 
77
83
  async function buildProject(isServe = false) {
78
- console.log('šŸ”Ø Building JUX project...\n');
84
+ console.log('šŸ”Ø Building JUX frontend...\n');
79
85
 
80
86
  try {
81
- // Clean and create dist
82
- if (fs.existsSync(PATHS.projectDist)) {
83
- fs.rmSync(PATHS.projectDist, { recursive: true, force: true });
87
+ // Verify jux source directory exists
88
+ if (!fs.existsSync(PATHS.juxSource)) {
89
+ console.error(`āŒ Source directory not found: ${PATHS.juxSource}`);
90
+ console.error(` Please create a 'jux/' directory with your .jux files`);
91
+ process.exit(1);
92
+ }
93
+
94
+ // Clean and create frontend dist
95
+ if (fs.existsSync(PATHS.frontendDist)) {
96
+ fs.rmSync(PATHS.frontendDist, { recursive: true, force: true });
84
97
  }
85
- fs.mkdirSync(PATHS.projectDist, { recursive: true });
98
+ fs.mkdirSync(PATHS.frontendDist, { recursive: true });
86
99
 
87
100
  // Step 1: Generate documentation from jux lib
88
101
  console.log('šŸ“š Generating documentation...');
@@ -93,21 +106,21 @@ async function buildProject(isServe = false) {
93
106
  console.warn('āš ļø Failed to generate docs:', error.message);
94
107
  }
95
108
 
96
- // Step 2: Copy jux lib to project dist
97
- await copyLibToOutput(PATHS.juxLib, PATHS.projectDist);
109
+ // Step 2: Copy jux lib to frontend dist
110
+ await copyLibToOutput(PATHS.juxLib, PATHS.frontendDist);
98
111
 
99
- // Step 3: Copy project assets (CSS, JS)
100
- await copyProjectAssets(PATHS.projectRoot, PATHS.projectDist);
112
+ // Step 3: Copy project assets from jux/ (CSS, JS, images)
113
+ await copyProjectAssets(PATHS.juxSource, PATHS.frontendDist);
101
114
 
102
- // Step 4: Compile project .jux files
103
- const projectJuxFiles = findJuxFiles(PATHS.projectRoot);
104
- console.log(`Found ${projectJuxFiles.length} project .jux file(s)\n`);
115
+ // Step 4: Compile .jux files from jux/ directory ONLY
116
+ const projectJuxFiles = findJuxFiles(PATHS.juxSource);
117
+ console.log(`Found ${projectJuxFiles.length} .jux file(s) in /jux\n`);
105
118
 
106
119
  for (const file of projectJuxFiles) {
107
120
  try {
108
121
  await compileJuxFile(file, {
109
- distDir: PATHS.projectDist,
110
- projectRoot: PATHS.projectRoot,
122
+ distDir: PATHS.frontendDist,
123
+ projectRoot: PATHS.juxSource,
111
124
  isServe
112
125
  });
113
126
  } catch (err) {
@@ -128,7 +141,7 @@ async function buildProject(isServe = false) {
128
141
  const relPath = path.relative(PATHS.juxLib, file);
129
142
 
130
143
  await compileJuxFile(file, {
131
- distDir: path.join(PATHS.projectDist, 'lib'),
144
+ distDir: path.join(PATHS.frontendDist, 'lib'),
132
145
  projectRoot: PATHS.juxLib,
133
146
  isServe
134
147
  });
@@ -140,7 +153,16 @@ async function buildProject(isServe = false) {
140
153
  }
141
154
  }
142
155
 
143
- console.log(`\nāœ… Built ${projectJuxFiles.length} project file(s) + layouts\n`);
156
+ console.log(`\nāœ… Built ${projectJuxFiles.length} file(s) → ${PATHS.frontendDist}\n`);
157
+
158
+ // Show backend integration examples
159
+ console.log('šŸ“¦ Serve from your backend:');
160
+ console.log(` Express: app.use(express.static('jux-dist'))`);
161
+ console.log(` Flask: app = Flask(__name__, static_folder='jux-dist')`);
162
+ console.log(` FastAPI: app.mount("/", StaticFiles(directory="jux-dist"), name="static")`);
163
+ console.log(` Laravel: Route::view('/', 'jux-dist/index.html')`);
164
+ console.log('');
165
+
144
166
  } catch (err) {
145
167
  console.error('āŒ Build error:', err.message);
146
168
  console.error(err.stack);
@@ -149,26 +171,105 @@ async function buildProject(isServe = false) {
149
171
  }
150
172
 
151
173
  (async () => {
152
- if (command === 'build') {
174
+ if (command === 'init') {
175
+ console.log('šŸŽØ Initializing JUX project...\n');
176
+
177
+ const juxDir = PATHS.juxSource;
178
+
179
+ if (fs.existsSync(juxDir)) {
180
+ console.error('āŒ jux/ directory already exists');
181
+ process.exit(1);
182
+ }
183
+
184
+ // Create structure
185
+ fs.mkdirSync(juxDir, { recursive: true });
186
+
187
+ // Copy template file from lib/templates/index.juxt
188
+ const templatePath = path.join(PATHS.packageRoot, 'lib', 'templates', 'index.juxt');
189
+ const targetPath = path.join(juxDir, 'index.jux');
190
+
191
+ if (fs.existsSync(templatePath)) {
192
+ fs.copyFileSync(templatePath, targetPath);
193
+ console.log('āœ… Created jux/index.jux from template');
194
+ } else {
195
+ // Fallback if template doesn't exist
196
+ console.warn('āš ļø Template not found, creating basic index.jux');
197
+ const fallbackContent = `// Welcome to JUX!
198
+ import { jux } from '/lib/jux.js';
199
+
200
+ jux.style('/lib/layouts/default.css');
201
+ jux.theme('light');
202
+
203
+ const header = jux.header('header').render("#app");
204
+ const main = jux.main('main').render("#app");
205
+ const footer = jux.footer('footer').render("#app");
206
+
207
+ jux.hero('hero1', {
208
+ title: 'Welcome to JUX',
209
+ subtitle: 'A JavaScript UX authorship platform'
210
+ }).render('#main');
211
+ `;
212
+ fs.writeFileSync(targetPath, fallbackContent);
213
+ console.log('āœ… Created jux/index.jux');
214
+ }
215
+
216
+ // Create .gitignore
217
+ const gitignorePath = path.join(PATHS.projectRoot, '.gitignore');
218
+ const gitignoreContent = `jux-dist/
219
+ node_modules/
220
+ .DS_Store
221
+ `;
222
+
223
+ if (!fs.existsSync(gitignorePath)) {
224
+ fs.writeFileSync(gitignorePath, gitignoreContent);
225
+ console.log('āœ… Created .gitignore');
226
+ }
227
+
228
+ console.log('āœ… Created jux/ directory\n');
229
+ console.log('Next steps:');
230
+ console.log(' 1. Edit jux/index.jux');
231
+ console.log(' 2. Run: npx jux build');
232
+ console.log(' 3. Serve jux-dist/ from your backend\n');
233
+
234
+ } else if (command === 'build') {
153
235
  await buildProject(false);
154
- console.log(`āœ… Build complete: ${PATHS.projectDist}`);
236
+ console.log(`āœ… Build complete: ${PATHS.frontendDist}`);
155
237
 
156
238
  } else if (command === 'serve') {
157
239
  await buildProject(true);
240
+
158
241
  const config = await loadConfig();
159
- await start(3000, config);
242
+ config.distDir = PATHS.frontendDist; // Pass the correct dist directory
243
+
244
+ const port = parseInt(process.argv[3]) || 3000;
245
+ await start(port, config);
160
246
 
161
247
  } else {
162
248
  console.log(`
163
249
  JUX CLI - A JavaScript UX authorship platform
164
250
 
165
251
  Usage:
166
- npx jux build Compile all .jux files to HTML/CSS/JS
252
+ npx jux init Initialize a new JUX project
253
+ npx jux build Compile .jux files from ./jux/ to ./jux-dist/
167
254
  npx jux serve [port] Start dev server with hot reload (default: 3000)
168
255
 
256
+ Project Structure (Convention):
257
+ my-project/
258
+ ā”œā”€ā”€ jux/ # Your .jux source files (REQUIRED)
259
+ │ ā”œā”€ā”€ index.jux
260
+ │ └── pages/
261
+ ā”œā”€ā”€ jux-dist/ # Build output (generated, git-ignore this)
262
+ ā”œā”€ā”€ server/ # Your backend (untouched by jux)
263
+ └── package.json
264
+
265
+ Getting Started:
266
+ 1. npx jux init # Create jux/ directory
267
+ 2. npx jux build # Build to jux-dist/
268
+ 3. Serve jux-dist/ from your backend
269
+
169
270
  Examples:
170
271
  npx jux build Build for production
171
- npx jux serve Start dev server (builds if needed)
272
+ npx jux serve Start dev server
172
273
  npx jux serve 8080 Start on port 8080
173
274
  `);
174
275
  }
@@ -1207,5 +1207,5 @@
1207
1207
  }
1208
1208
  ],
1209
1209
  "version": "1.0.0",
1210
- "lastUpdated": "2026-01-16T22:00:11.522Z"
1210
+ "lastUpdated": "2026-01-16T23:06:56.674Z"
1211
1211
  }
@@ -0,0 +1,33 @@
1
+ // Welcome to JUX!
2
+ import { code } from '/lib/components/code.js';
3
+ import { jux } from '/lib/jux.js';
4
+
5
+ jux.style('/lib/layouts/notion.css');
6
+ jux.theme('light');
7
+
8
+ const appheader = jux.header('appheader', {}).render("#app");
9
+ const appsubheader = jux.header('appsubheader', {}).render("#app");
10
+ const appsidebar = jux.sidebar('appsidebar', {}).render("#app");
11
+ const appmain = jux.main('appmain', {}).render("#app");
12
+ const appaside = jux.sidebar('appaside', {}).render("#app");
13
+ const appfooter = jux.footer('appfooter', {}).render("#app");
14
+ const appmodal = jux.modal('appmodal', {}).render("#app");
15
+
16
+
17
+ await jux.hero('hero1', {
18
+ title: 'Welcome to JUX',
19
+ subtitle: 'A JavaScript UX authorship platform'
20
+ }).render();
21
+
22
+ const code1 = code('code1').code(`Serve from your backend:
23
+ Express: app.use(express.static('jux-dist'))
24
+ Flask: app = Flask(__name__, static_folder='jux-dist')
25
+ FastAPI: app.mount("/", StaticFiles(directory="jux-dist"), name="static")
26
+ Laravel: Route::view('/', 'jux-dist/index.html')`)
27
+ .language('bash');
28
+
29
+ code1.render();
30
+
31
+ // note
32
+ // render()
33
+ // renderTo()
@@ -12,7 +12,7 @@ const __dirname = path.dirname(__filename);
12
12
 
13
13
  let db = null;
14
14
 
15
- async function serve(port = 3000, distDir = './dist') {
15
+ async function serve(port = 3000, distDir = './jux-dist') { // Changed default
16
16
  const app = express();
17
17
  const absoluteDistDir = path.resolve(distDir);
18
18
  const projectRoot = path.resolve('.');
@@ -20,8 +20,8 @@ async function serve(port = 3000, distDir = './dist') {
20
20
  app.use(express.json());
21
21
 
22
22
  if (!fs.existsSync(absoluteDistDir)) {
23
- console.error(`Error: dist directory not found at ${absoluteDistDir}`);
24
- console.log('Building project first...\n');
23
+ console.error(`āŒ Error: ${path.basename(distDir)}/ directory not found at ${absoluteDistDir}`);
24
+ console.error(' Run: npx jux build\n');
25
25
  process.exit(1);
26
26
  }
27
27
 
@@ -146,16 +146,23 @@ async function serve(port = 3000, distDir = './dist') {
146
146
  // Start HTTP server
147
147
  server.listen(port, () => {
148
148
  console.log(`šŸš€ JUX dev server running at http://localhost:${port}`);
149
+ console.log(` Serving: ${absoluteDistDir}`);
150
+ console.log(` Press Ctrl+C to stop\n`);
149
151
  });
150
152
 
151
153
  // Start file watcher
152
- startWatcher(projectRoot, absoluteDistDir, clients);
154
+ const juxSource = path.join(projectRoot, 'jux');
155
+ if (fs.existsSync(juxSource)) {
156
+ console.log(`šŸ‘€ Watching: ${juxSource}\n`);
157
+ startWatcher(juxSource, absoluteDistDir, clients);
158
+ }
153
159
 
154
160
  // Graceful shutdown
155
161
  const shutdown = async () => {
156
162
  console.log('\n\nšŸ‘‹ Shutting down server...');
157
163
  wss.close();
158
164
  server.close();
165
+ if (db) db = null;
159
166
  process.exit(0);
160
167
  };
161
168
 
@@ -181,5 +188,5 @@ async function initDatabase() {
181
188
 
182
189
  export async function start(port = 3000, config = {}) {
183
190
  await initDatabase();
184
- return serve(port, config.distDir || './dist');
191
+ return serve(port, config.distDir || './jux-dist'); // Changed default
185
192
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "lib/jux.js",