als-layout 4.2.0 → 4.3.0

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/docs/4-view.md ADDED
@@ -0,0 +1,19 @@
1
+ ## View method
2
+
3
+ **The view method is a pilot. Don't use in production.**
4
+
5
+ ```js
6
+ Layout.viewsPath = '../../views'; // relative to layout path
7
+ Layout.publicPath = '../../public'; // public folder path for urls starts with "/" should be relative to root
8
+ Layout.dev = false; // true by default
9
+
10
+ const data = {};
11
+ const includeBundle = false; // true by default
12
+ layout.view('some/Test',data,includeBundle) // viewsPath/some/Test.js
13
+ layout.view('some/test',data,includeBundle) // viewsPath/some/test/Index.js
14
+
15
+ ```
16
+
17
+ * `includeBundle`
18
+ * in dev mode, will include bundle for rendering inside script tag in html
19
+ * in prod mode, will save context and bundle as files in publicPath/js folder and will add script[src] to html for those files.
package/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  const { Document, SingleNode, Node } = require('als-document');
2
2
  const UglifyJS = require("uglify-js");
3
3
  const uglifycss = require('uglifycss');
4
+ const { join, dirname } = require('path')
5
+ const { writeFileSync, mkdirSync } = require('fs')
6
+ const Render = require('als-render')
4
7
 
5
8
  const onloadScript = /*js*/`document.addEventListener('DOMContentLoaded', function() {
6
9
  const elements = document.querySelectorAll('[onload]');
@@ -13,16 +16,20 @@ const onloadScript = /*js*/`document.addEventListener('DOMContentLoaded', functi
13
16
  });`;
14
17
 
15
18
  class Layout extends Document {
16
- get rawHtml() { return this.innerHTML }
17
- get clone() { return new Layout(new Document(this), this.URL, this.minified) }
18
- lang(lang) { this.html.setAttribute('lang', lang); return this }
19
-
19
+ static bundles = {};
20
+ static viewsPath = '../../views';
21
+ static publicPath = '../../public';
22
+ static dev = true;
20
23
  constructor(html, host, minified = false) {
21
24
  super(html, host);
22
25
  this.minified = minified
23
26
  this.root = this.html
24
27
  }
25
28
 
29
+ get rawHtml() { return this.innerHTML }
30
+ get clone() { return new Layout(new Document(this), this.URL, this.minified) }
31
+ lang(lang) { this.html.setAttribute('lang', lang); return this }
32
+
26
33
  onload() {
27
34
  if (this.onloadAdded) return
28
35
  this.script({}, onloadScript);
@@ -143,6 +150,33 @@ class Layout extends Document {
143
150
  this.head.insert(2, linkElement)
144
151
  return this
145
152
  }
153
+
154
+ view(path, data = {}, includeBundle=true) {
155
+ const parts = path.split('/')
156
+ if(parts[parts.length-1][0].toUpperCase() !== parts[parts.length-1][0]) parts.push('Index.js')
157
+ const relativePath = join(Layout.viewsPath, ...parts)
158
+ const { bundle, bundleFn, callBundle, rawHtml, context } = Render.render(relativePath, data, !Layout.dev)
159
+ if (includeBundle) {
160
+ if (Layout.dev) this.script({}, bundle, false)
161
+ else {
162
+ this.write('context', context, true)
163
+ this.write(path, bundleFn, false)
164
+ this.script({}, callBundle, false)
165
+ }
166
+ }
167
+ const element = /*html*/`<content></content>`
168
+ this.body.insertAdjacentHTML('afterbegin', element)
169
+ return this.rawHtml.replace(element, rawHtml)
170
+ }
171
+
172
+ write(path, content, head) {
173
+ if (Layout.bundles[path]) return
174
+ const filePath = join(Layout.publicPath, 'js', path + '.js')
175
+ mkdirSync(dirname(filePath), { recursive: true })
176
+ writeFileSync(filePath, content)
177
+ Layout.bundles[path] = path
178
+ this.script({ src: `/js/${path}.js` }, '', head)
179
+ }
146
180
  }
147
181
 
148
182
  module.exports = Layout
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "als-layout",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "node --test --experimental-test-coverage",
@@ -12,7 +12,11 @@
12
12
  "description": "Html layout constructor",
13
13
  "dependencies": {
14
14
  "als-document": "^1.4.0",
15
+ "als-render": "^0.9.3",
15
16
  "uglify-js": "^3.19.2",
16
17
  "uglifycss": "^0.0.29"
18
+ },
19
+ "devDependencies": {
20
+ "fs-extra": "^11.2.0"
17
21
  }
18
22
  }
package/readme.md CHANGED
@@ -152,3 +152,23 @@ In this example:
152
152
  - We dynamically add a versioned link to a stylesheet in the `homePage`, demonstrating control over caching and resource management.
153
153
 
154
154
  This advanced example illustrates how `als-layout` can be used to handle complex scenarios and requirements in web development, enhancing the flexibility and power at your disposal.
155
+
156
+ ## View method
157
+
158
+ **The view method is a pilot. Don't use in production.**
159
+
160
+ ```js
161
+ Layout.viewsPath = '../../views'; // relative to layout path
162
+ Layout.publicPath = '../../public'; // public folder path for urls starts with "/" should be relative to root
163
+ Layout.dev = false; // true by default
164
+
165
+ const data = {};
166
+ const includeBundle = false; // true by default
167
+ layout.view('some/Test',data,includeBundle) // viewsPath/some/Test.js
168
+ layout.view('some/test',data,includeBundle) // viewsPath/some/test/Index.js
169
+
170
+ ```
171
+
172
+ * `includeBundle`
173
+ * in dev mode, will include bundle for rendering inside script tag in html
174
+ * in prod mode, will save context and bundle as files in publicPath/js folder and will add script[src] to html for those files.
@@ -0,0 +1,72 @@
1
+ const assert = require('assert');
2
+ const { describe, it, beforeEach, before, afterEach } = require('node:test')
3
+ const Layout = require('../index');
4
+ const { readdirSync, removeSync, existsSync, rmdirSync } = require('fs-extra')
5
+ const { join } = require('path')
6
+ Layout.viewsPath = 'views';
7
+ Layout.publicPath = join(__dirname,'public')
8
+
9
+ describe('Dev mode', () => {
10
+ let layout
11
+ before(() => {
12
+ Layout.dev = true;
13
+ })
14
+ beforeEach(() => {
15
+ layout = new Layout()
16
+ })
17
+
18
+ it('view path without bundle', () => {
19
+ const html = layout.view('App', { test: 'test' })
20
+ assert(html.includes(/*html*/`<div component="App">Hello test</div>`))
21
+ assert(!html.includes(/*html*/`<content></content>`))
22
+ })
23
+
24
+ it('view Index path without bundle', () => {
25
+ const html = layout.view('app', { test: 'test' })
26
+ assert(html.includes(/*html*/`<div component="Index">Hello test</div>`))
27
+ assert(!html.includes(/*html*/`<content></content>`))
28
+ })
29
+
30
+ it('view path with bundle', () => {
31
+ const html = layout.view('App', { test: 'test' }, true)
32
+ assert(html.includes('const Context'))
33
+ assert(html.includes('renderedBundle'))
34
+ })
35
+
36
+ })
37
+
38
+ describe('Prod mode', () => {
39
+ let layout
40
+ const publicPath = join(Layout.publicPath,'js')
41
+ before(() => {
42
+ Layout.dev = false;
43
+ })
44
+ beforeEach(() => {
45
+ layout = new Layout()
46
+ })
47
+
48
+ afterEach(() => {
49
+ if(!existsSync(publicPath)) return
50
+ const files = readdirSync(publicPath)
51
+ files.forEach(file => removeSync(join(publicPath,file)))
52
+ if(existsSync(publicPath)) rmdirSync(publicPath)
53
+ })
54
+
55
+ it('view path without bundle', () => {
56
+ const html = layout.view('App', { test: 'test' })
57
+ assert(html.includes(/*html*/`<div component="App">Hello test</div>`))
58
+ assert(!html.includes(/*html*/`<content></content>`))
59
+ assert(existsSync(publicPath) === false)
60
+ })
61
+
62
+ it('view path with bundle', () => {
63
+ const html = layout.view('App', { test: 'test' }, true)
64
+ const files = readdirSync(publicPath)
65
+ assert.deepStrictEqual(files,[ 'App.js', 'context.js' ])
66
+ assert(html.includes('/js/App.js'))
67
+ assert(html.includes('renderedBundle'))
68
+ // <script src="/js/App.js"></script><script>renderedBundle({"test":"test"})</script>
69
+ })
70
+
71
+ })
72
+
@@ -0,0 +1,5 @@
1
+ function App(props={}) {
2
+ return (<div>Hello {props.test}</div>)
3
+ }
4
+
5
+ module.exports = App
@@ -0,0 +1,5 @@
1
+ function Index(props={}) {
2
+ return (<div>Hello {props.test}</div>)
3
+ }
4
+
5
+ module.exports = Index