@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.
Files changed (3) hide show
  1. package/README.md +13 -29
  2. package/index.js +60 -238
  3. 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 an integration for [Vituum](https://vituum.dev), and contains set of tools that can be used to create modern web applications.
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 tool at [Newlogic Digital](https://www.newlogic.cz/) to create wonders.
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 and [Tailwind CSS](https://tailwindcss.com/) for utility classes.
30
- * **[TwigJS](https://github.com/vituum/vite-plugin-twig)** as template engine twig
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 defineConfig({
69
- integrations: [core()]
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 fse from 'fs-extra'
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
- import tailwindcss from 'tailwindcss'
13
- import tailwindcssNesting from 'tailwindcss/nesting/index.js'
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: '@vituum/vite-plugin-posthtml-prism',
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.endsWith('ui.json') && !filename.endsWith('ui.vituum.json.html')) {
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
- const defaultConfig = {
87
- format: 'twig',
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
- tailwind: {},
95
- twig: {
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
- isStringFilter: (filename) => dirname(filename).endsWith('email'),
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
- const integration = (userConfig = {}) => {
266
- userConfig = lodash.merge(defaultConfig, userConfig)
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
- config: {
270
- integrations: [posthtml(userConfig.posthtml), juice(userConfig.juice), twig(userConfig.twig), latte(userConfig.latte), {
271
- task: {
272
- name: 'emails',
273
- action: async () => {
274
- const emails = FastGlob.sync(`${resolve(process.cwd(), userConfig.emails.outputDir)}/**`).filter(entry => !entry.endsWith('test.html'))
275
- const emailsProd = emails.map(path => {
276
- return path.replace(resolve(process.cwd(), userConfig.emails.outputDir), resolve(process.cwd(), userConfig.emails.appDir)).replace('.html', '.latte')
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
- console.info(`${chalk.cyan(`newlogic-core`)} ${chalk.green('all email files moved')}`)
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 integration
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": "1.1.1",
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
- "npm-publish": "npm publish --tag next"
10
+ "tsc": "tsc",
11
+ "eslint": "eslint '**/*.js' --fix"
11
12
  },
12
13
  "dependencies": {
13
- "@vituum/posthtml": "^0.1.0",
14
- "@vituum/juice": "^0.1.5",
15
- "@vituum/twig": "^0.1.1",
16
- "@vituum/latte": "^0.1.1",
17
- "tailwindcss": "^3.3.1",
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
- "vituum": "^0.0.42"
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",