@newlogic-digital/core 1.1.1 → 2.0.0-alpha.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.
- package/README.md +13 -29
- package/index.js +60 -238
- package/package.json +18 -9
package/README.md
CHANGED
@@ -19,58 +19,42 @@ Starter for creating web applications. Powered by Vite and Vituum.
|
|
19
19
|
- 📦 Modular structure
|
20
20
|
- ✉️ Email templates
|
21
21
|
|
22
|
-
Newlogic Core is
|
22
|
+
Newlogic Core is a plugin for [Vite](https://vitejs.dev), and contains set of plugins that can be used to create modern web applications.
|
23
23
|
|
24
|
-
We use it as our main front-end
|
24
|
+
We use it as our main front-end set of tools at [Newlogic Digital](https://www.newlogic.cz/) to create wonders.
|
25
25
|
|
26
26
|
## 🛠️ Integrated tools
|
27
27
|
* **[Vite](https://vitejs.dev)** next-generation frontend tooling
|
28
28
|
* **[Vituum](https://vituum.dev)** fast prototyping with template engines
|
29
|
-
* **[PostCSS](https://postcss.org/)** with basic plugins
|
30
|
-
* **[
|
29
|
+
* **[PostCSS](https://postcss.org/)** with basic plugins
|
30
|
+
* **[TailwindCSS](https://tailwindcss.com/)** for utility classes
|
31
31
|
* **[Latte](https://github.com/vituum/vite-plugin-latte)** as template engine latte
|
32
32
|
|
33
|
-
### 💡 Basic principle
|
34
|
-
|
35
|
-
Most of today build tools are hard to configure and not focused primary on PHP server side applications.
|
36
|
-
|
37
|
-
PHP programmers often **don't want to configure anything**, basic idea is to add as many files you want to `src` and get output in `public/assets` - without worrying about anything.
|
38
|
-
|
39
|
-
It doesn't matter if you use Nette, Symfony or Laravel - the structure can be freely adjusted as needed - `resources` and` public`, `src` and` dist` or `app/assets` and` www`
|
40
|
-
|
41
|
-
It's up to you - all paths are freely configurable via `vite.config.js` config
|
42
|
-
|
43
|
-
### 📦 Modularity
|
44
|
-
|
45
|
-
Newlogic Core uses [Vituum](https://vituum.dev) and [Vite](https://vitejs.dev) for frontend tooling.
|
46
|
-
|
47
|
-
Source files are divided by modules inside `src` directory - styles, scripts, templates, data, emails, assets. It is optional which modules you want to use for the project, simple delete the directory. You really only use what you want to use.
|
48
|
-
|
49
33
|
## 🪄 Get started
|
50
34
|
|
51
35
|
```sh
|
52
36
|
npm i @newlogic-digital/core --save-dev
|
53
37
|
```
|
54
38
|
|
55
|
-
### Requirements
|
56
|
-
|
57
|
-
- [Node.js LTS (16.x)](https://nodejs.org/en/download/)
|
58
|
-
- [Vituum](https://vituum.dev/)
|
59
|
-
|
60
39
|
### Config
|
61
40
|
|
62
41
|
Each **Newlogic Core** project needs to have config via `vite.config.js`
|
63
42
|
|
64
43
|
```js
|
65
|
-
import { defineConfig } from 'vituum'
|
66
44
|
import core from "@newlogic-digital/core"
|
67
45
|
|
68
|
-
export default
|
69
|
-
|
70
|
-
}
|
46
|
+
export default {
|
47
|
+
plugins: [core()]
|
48
|
+
}
|
71
49
|
```
|
72
50
|
|
73
51
|
You can also try minimal example project [core-starter](https://github.com/newlogic-digital/core-starter)
|
74
52
|
|
53
|
+
### Requirements
|
54
|
+
|
55
|
+
- [Node.js LTS (18.x)](https://nodejs.org/en/download/)
|
56
|
+
- [Vite](https://vitejs.dev/)
|
57
|
+
- [PHP 8.2](https://www.php.net/) for Latte support
|
58
|
+
|
75
59
|
## Licence
|
76
60
|
MIT
|
package/index.js
CHANGED
@@ -1,37 +1,32 @@
|
|
1
|
-
import posthtml from '@vituum/posthtml'
|
2
|
-
import juice from '@vituum/juice'
|
3
|
-
import twig from '@vituum/twig'
|
4
|
-
import latte from '@vituum/latte'
|
5
|
-
import lodash from 'lodash'
|
6
|
-
import minifier from 'html-minifier-terser'
|
7
1
|
import fs from 'fs'
|
8
|
-
import
|
9
|
-
import { dirname, resolve } from 'path'
|
2
|
+
import os from 'os'
|
3
|
+
import { dirname, resolve, join } from 'path'
|
10
4
|
import postHtml from 'posthtml'
|
5
|
+
import vituum from 'vituum'
|
6
|
+
import posthtml from '@vituum/vite-plugin-posthtml'
|
7
|
+
import latte from '@vituum/vite-plugin-latte'
|
8
|
+
import juice from '@vituum/vite-plugin-juice'
|
9
|
+
import send from '@vituum/vite-plugin-send'
|
10
|
+
import tailwindcss from '@vituum/vite-plugin-tailwindcss'
|
11
|
+
import { getPackageInfo, merge } from 'vituum/utils/common.js'
|
12
|
+
import minifier from 'html-minifier-terser'
|
11
13
|
import highlight from './prism.js'
|
12
|
-
|
13
|
-
|
14
|
-
import postcssImport from 'postcss-import'
|
15
|
-
import postcssNesting from 'postcss-nesting'
|
16
|
-
import postcssCustomMedia from 'postcss-custom-media'
|
17
|
-
import postcssCustomSelectors from 'postcss-custom-selectors'
|
18
|
-
import autoprefixer from 'autoprefixer'
|
19
|
-
import chalk from 'chalk'
|
20
|
-
import FastGlob from 'fast-glob'
|
14
|
+
|
15
|
+
const { name } = getPackageInfo(import.meta.url)
|
21
16
|
|
22
17
|
const posthtmlPrism = {
|
23
|
-
name: '@
|
18
|
+
name: '@newlogic-digital/vite-plugin-posthtml-prism',
|
24
19
|
enforce: 'post',
|
25
20
|
transformIndexHtml: {
|
26
21
|
enforce: 'post',
|
27
|
-
transform: async(html, { filename }) => {
|
22
|
+
transform: async (html, { filename }) => {
|
28
23
|
filename = filename.replace('?raw', '')
|
29
24
|
|
30
|
-
if (!filename.
|
25
|
+
if (!filename.replace('.html', '').endsWith('ui.json')) {
|
31
26
|
return
|
32
27
|
}
|
33
28
|
|
34
|
-
const plugins = [highlight({ inline: false
|
29
|
+
const plugins = [highlight({ inline: false })]
|
35
30
|
|
36
31
|
const result = await postHtml(plugins).process(html)
|
37
32
|
|
@@ -40,30 +35,6 @@ const posthtmlPrism = {
|
|
40
35
|
}
|
41
36
|
}
|
42
37
|
|
43
|
-
const wrapPreCode = (code, lang) => {
|
44
|
-
return `<pre class="language-${lang}"><code class="language-${lang}">${code}</code></pre>`
|
45
|
-
}
|
46
|
-
|
47
|
-
const stripIndent = (string) => {
|
48
|
-
const indent = () => {
|
49
|
-
const match = string.match(/^[ \t]*(?=\S)/gm)
|
50
|
-
|
51
|
-
if (!match) {
|
52
|
-
return 0
|
53
|
-
}
|
54
|
-
|
55
|
-
return match.reduce((r, a) => Math.min(r, a.length), Infinity)
|
56
|
-
}
|
57
|
-
|
58
|
-
if (indent() === 0) {
|
59
|
-
return string
|
60
|
-
}
|
61
|
-
|
62
|
-
const regex = new RegExp(`^[ \\t]{${indent()}}`, 'gm')
|
63
|
-
|
64
|
-
return string.replace(regex, '')
|
65
|
-
}
|
66
|
-
|
67
38
|
const parseMinifyHtml = async (input, name) => {
|
68
39
|
const minify = await minifier.minify(input, {
|
69
40
|
collapseWhitespace: true,
|
@@ -83,163 +54,22 @@ const parseMinifyHtml = async (input, name) => {
|
|
83
54
|
}
|
84
55
|
}
|
85
56
|
|
86
|
-
|
87
|
-
|
57
|
+
/**
|
58
|
+
* @type {import('@newlogic-digital/core/types').PluginUserConfig}
|
59
|
+
*/
|
60
|
+
const defaultOptions = {
|
61
|
+
cert: 'localhost',
|
88
62
|
emails: {
|
89
63
|
outputDir: resolve(process.cwd(), 'public/email'),
|
90
64
|
appDir: resolve(process.cwd(), 'app/Templates/Emails')
|
91
65
|
},
|
66
|
+
vituum: {},
|
92
67
|
posthtml: {},
|
93
68
|
juice: {},
|
94
|
-
|
95
|
-
|
96
|
-
namespaces: {
|
97
|
-
src: resolve(process.cwd(), 'src'),
|
98
|
-
templates: resolve(process.cwd(), 'src/templates')
|
99
|
-
},
|
100
|
-
functions: {
|
101
|
-
pages: () => {
|
102
|
-
return fs.readdirSync('src/views').filter(file => fs.statSync('src/views/' + file).isFile())
|
103
|
-
},
|
104
|
-
fetch: (data) => {
|
105
|
-
if (typeof data !== 'undefined') {
|
106
|
-
if (data.indexOf('http') > -1) {
|
107
|
-
return data
|
108
|
-
} else {
|
109
|
-
let slash = data.indexOf('/') + 1
|
110
|
-
if (slash > 1) {
|
111
|
-
slash = 0
|
112
|
-
}
|
113
|
-
|
114
|
-
return fs.readFileSync(process.cwd() + '/' + data.substring(slash, data.length), 'utf8').toString()
|
115
|
-
}
|
116
|
-
}
|
117
|
-
},
|
118
|
-
randomColor: () => {
|
119
|
-
return '#' + Math.random().toString(16).slice(2, 8)
|
120
|
-
},
|
121
|
-
placeholder: (width, height) => {
|
122
|
-
const colors = ['333', '444', '666', '222', '777', '888', '111']
|
123
|
-
return 'https://via.placeholder.com/' + width + 'x' + height + '/' + colors[Math.floor(Math.random() * colors.length)] + '.webp'
|
124
|
-
},
|
125
|
-
lazy: (width, height) => {
|
126
|
-
const svg = encodeURIComponent(stripIndent('<svg width="' + width + '" height="' + height + '" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + width + ' ' + height + '"></svg>'))
|
127
|
-
|
128
|
-
return 'data:image/svg+xml;charset=UTF-8,' + svg
|
129
|
-
},
|
130
|
-
ratio: (width, height) => {
|
131
|
-
return (height / width) * 100
|
132
|
-
}
|
133
|
-
},
|
134
|
-
filters: {
|
135
|
-
asset: (url) => {
|
136
|
-
return url.replace('/src/', '/')
|
137
|
-
},
|
138
|
-
rem: (value) => {
|
139
|
-
return `${value / 16}rem`
|
140
|
-
},
|
141
|
-
encode64: (path) => {
|
142
|
-
const svg = encodeURIComponent(stripIndent(path))
|
143
|
-
|
144
|
-
return 'data:image/svg+xml;charset=UTF-8,' + svg
|
145
|
-
},
|
146
|
-
exists: (path) => {
|
147
|
-
if (path.indexOf('/') === 0) {
|
148
|
-
path = path.slice(1)
|
149
|
-
}
|
150
|
-
|
151
|
-
return fs.existsSync(resolve(process.cwd(), path))
|
152
|
-
},
|
153
|
-
tel: (value) => {
|
154
|
-
return value.replace(/\s+/g, '').replace('(', '').replace(')', '')
|
155
|
-
}
|
156
|
-
},
|
157
|
-
extensions: [
|
158
|
-
(Twig) => {
|
159
|
-
Twig.exports.extendTag({
|
160
|
-
type: 'json',
|
161
|
-
regex: /^json\s+(.+)$|^json$/,
|
162
|
-
next: ['endjson'],
|
163
|
-
open: true,
|
164
|
-
compile: function(token) {
|
165
|
-
const expression = token.match[1] ?? '\'_null\''
|
166
|
-
|
167
|
-
token.stack = Reflect.apply(Twig.expression.compile, this, [{
|
168
|
-
type: Twig.expression.type.expression,
|
169
|
-
value: expression
|
170
|
-
}]).stack
|
171
|
-
|
172
|
-
delete token.match
|
173
|
-
return token
|
174
|
-
},
|
175
|
-
parse: async function(token, context, chain) {
|
176
|
-
const name = Reflect.apply(Twig.expression.parse, this, [token.stack, context])
|
177
|
-
const output = this.parse(token.output, context)
|
178
|
-
|
179
|
-
if (name === '_null') {
|
180
|
-
return {
|
181
|
-
chain,
|
182
|
-
output: await parseMinifyHtml(output)
|
183
|
-
}
|
184
|
-
} else {
|
185
|
-
return {
|
186
|
-
chain,
|
187
|
-
output: await parseMinifyHtml(output, name)
|
188
|
-
}
|
189
|
-
}
|
190
|
-
}
|
191
|
-
})
|
192
|
-
Twig.exports.extendTag({
|
193
|
-
type: 'endjson',
|
194
|
-
regex: /^endjson$/,
|
195
|
-
next: [],
|
196
|
-
open: false
|
197
|
-
})
|
198
|
-
},
|
199
|
-
(Twig) => {
|
200
|
-
Twig.exports.extendTag({
|
201
|
-
type: "code",
|
202
|
-
regex: /^code\s+(.+)$/,
|
203
|
-
next: ["endcode"], // match the type of the end tag
|
204
|
-
open: true,
|
205
|
-
compile: function (token) {
|
206
|
-
const expression = token.match[1];
|
207
|
-
|
208
|
-
token.stack = Reflect.apply(Twig.expression.compile, this, [{
|
209
|
-
type: Twig.expression.type.expression,
|
210
|
-
value: expression
|
211
|
-
}]).stack;
|
212
|
-
|
213
|
-
delete token.match;
|
214
|
-
return token;
|
215
|
-
},
|
216
|
-
parse: function (token, context, chain) {
|
217
|
-
let type = Reflect.apply(Twig.expression.parse, this, [token.stack, context]);
|
218
|
-
let output = this.parse(token.output, context);
|
219
|
-
let mirror = false;
|
220
|
-
|
221
|
-
if (type.includes(":mirror")) {
|
222
|
-
mirror = true;
|
223
|
-
type = type.replace(":mirror", "")
|
224
|
-
}
|
225
|
-
|
226
|
-
return {
|
227
|
-
chain: chain,
|
228
|
-
output: `${mirror ? output : ""}${wrapPreCode(output, type)}`
|
229
|
-
};
|
230
|
-
}
|
231
|
-
});
|
232
|
-
Twig.exports.extendTag({
|
233
|
-
type: "endcode",
|
234
|
-
regex: /^endcode$/,
|
235
|
-
next: [ ],
|
236
|
-
open: false
|
237
|
-
});
|
238
|
-
}
|
239
|
-
]
|
240
|
-
},
|
69
|
+
tailwindcss: {},
|
70
|
+
send: {},
|
241
71
|
latte: {
|
242
|
-
|
72
|
+
renderTransformedHtml: (filename) => dirname(filename).endsWith('email'),
|
243
73
|
globals: {
|
244
74
|
srcPath: resolve(process.cwd(), 'src'),
|
245
75
|
templatesPath: resolve(process.cwd(), 'src/templates')
|
@@ -256,58 +86,50 @@ const defaultConfig = {
|
|
256
86
|
code: 'node_modules/@newlogic-digital/core/latte/CodeFilter.php'
|
257
87
|
},
|
258
88
|
ignoredPaths: ['**/views/email/**/!(*.test).latte']
|
259
|
-
},
|
260
|
-
postcssNesting: {
|
261
|
-
noIsPseudoSelector: true
|
262
89
|
}
|
263
90
|
}
|
264
91
|
|
265
|
-
|
266
|
-
|
92
|
+
/**
|
93
|
+
* @param {import('@newlogic-digital/core/types').PluginUserConfig} options
|
94
|
+
* @returns import('vite').Plugin
|
95
|
+
*/
|
96
|
+
const plugin = (options = {}) => {
|
97
|
+
options = merge(defaultOptions, options)
|
98
|
+
|
99
|
+
const plugins = [
|
100
|
+
vituum(options.vituum),
|
101
|
+
tailwindcss(options.tailwindcss),
|
102
|
+
posthtml(options.posthtml),
|
103
|
+
latte(options.latte),
|
104
|
+
juice(options.juice),
|
105
|
+
send(options.send),
|
106
|
+
posthtmlPrism
|
107
|
+
]
|
267
108
|
|
268
109
|
return {
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
})
|
278
|
-
|
279
|
-
await Promise.all(emails.map((file, i) =>
|
280
|
-
fse.move(file, emailsProd[i], { overwrite: true })
|
281
|
-
))
|
110
|
+
name,
|
111
|
+
enforce: 'pre',
|
112
|
+
config (userConfig) {
|
113
|
+
if (!userConfig?.plugins) {
|
114
|
+
userConfig.plugins = plugins
|
115
|
+
} else if (userConfig.plugins) {
|
116
|
+
userConfig.plugins = plugins.concat(...userConfig.plugins)
|
117
|
+
}
|
282
118
|
|
283
|
-
|
119
|
+
if (
|
120
|
+
userConfig?.server?.https !== false &&
|
121
|
+
fs.existsSync(join(os.homedir(), `.ssh/${options.cert}.pem`)) &&
|
122
|
+
fs.existsSync(join(os.homedir(), `.ssh/${options.cert}-key.pem`))
|
123
|
+
) {
|
124
|
+
userConfig.server = Object.assign(userConfig.server ?? {}, {
|
125
|
+
https: {
|
126
|
+
key: fs.readFileSync(join(os.homedir(), `.ssh/${options.cert}-key.pem`)),
|
127
|
+
cert: fs.readFileSync(join(os.homedir(), `.ssh/${options.cert}.pem`))
|
284
128
|
}
|
285
|
-
}
|
286
|
-
}],
|
287
|
-
plugins: [posthtmlPrism],
|
288
|
-
server: {
|
289
|
-
open: true,
|
290
|
-
https: true,
|
291
|
-
reload: file => (file.endsWith('.tpl') || file.endsWith('.latte')) && !file.includes('temp/')
|
292
|
-
},
|
293
|
-
templates: {
|
294
|
-
format: userConfig.format
|
295
|
-
},
|
296
|
-
imports: {
|
297
|
-
paths: ['./src/styles/**', './src/scripts/**', '!./src/styles/Utils/**']
|
298
|
-
},
|
299
|
-
vite: {
|
300
|
-
server: {
|
301
|
-
origin: fs.existsSync(resolve(process.cwd(), 'app/settings.php')) ? (fs.readFileSync(resolve(process.cwd(), 'app/settings.php')).toString().match(/VITE_URL = '(.+)';/) || [null, null])[1] : null
|
302
|
-
},
|
303
|
-
css: {
|
304
|
-
postcss: {
|
305
|
-
plugins: [postcssImport, tailwindcssNesting(postcssNesting(userConfig.postcssNesting)), postcssCustomMedia, postcssCustomSelectors, tailwindcss(userConfig.tailwind), autoprefixer]
|
306
|
-
}
|
307
|
-
}
|
129
|
+
})
|
308
130
|
}
|
309
131
|
}
|
310
132
|
}
|
311
133
|
}
|
312
134
|
|
313
|
-
export default
|
135
|
+
export default plugin
|
package/package.json
CHANGED
@@ -1,25 +1,34 @@
|
|
1
1
|
{
|
2
2
|
"name": "@newlogic-digital/core",
|
3
3
|
"type": "module",
|
4
|
-
"version": "
|
4
|
+
"version": "2.0.0-alpha.1",
|
5
5
|
"main": "index.js",
|
6
6
|
"author": "New Logic Studio s.r.o.",
|
7
7
|
"description": "Set of tools that can be used to create modern web applications",
|
8
8
|
"license": "MIT",
|
9
9
|
"scripts": {
|
10
|
-
"
|
10
|
+
"tsc": "tsc",
|
11
|
+
"eslint": "eslint '**/*.js' --fix"
|
11
12
|
},
|
12
13
|
"dependencies": {
|
13
|
-
"@vituum/posthtml": "^0.
|
14
|
-
"@vituum/juice": "^0.1
|
15
|
-
"@vituum/
|
16
|
-
"@vituum/
|
17
|
-
"
|
14
|
+
"@vituum/vite-plugin-posthtml": "^1.0.0-alpha.3",
|
15
|
+
"@vituum/vite-plugin-juice": "^1.0.0-alpha.1",
|
16
|
+
"@vituum/vite-plugin-latte": "^1.0.0-alpha.3",
|
17
|
+
"@vituum/vite-plugin-tailwindcss": "^1.0.0-alpha.1",
|
18
|
+
"@vituum/vite-plugin-send": "^1.0.0-alpha.1",
|
19
|
+
"vituum": "^1.0.0-alpha.16",
|
20
|
+
"posthtml": "^0.16.6",
|
18
21
|
"posthtml-prism": "^2.0.0",
|
19
22
|
"prismjs": "^1.29.0",
|
20
23
|
"html-minifier-terser": "^7.2.0",
|
21
|
-
"lodash": "^4.17.21"
|
22
|
-
|
24
|
+
"lodash": "^4.17.21"
|
25
|
+
},
|
26
|
+
"devDependencies": {
|
27
|
+
"@types/node": "^20.3.1",
|
28
|
+
"eslint": "^8.42.0",
|
29
|
+
"eslint-config-standard": "^17.1.0",
|
30
|
+
"typescript": "^5.1.3",
|
31
|
+
"vite": "^4.3.9"
|
23
32
|
},
|
24
33
|
"files": [
|
25
34
|
"latte",
|