neo.mjs 9.5.0 → 9.6.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/apps/ServiceWorker.mjs +2 -2
- package/apps/portal/index.html +1 -1
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/apps/portal/view/learn/MainContainerStateProvider.mjs +2 -2
- package/buildScripts/buildAll.mjs +14 -7
- package/buildScripts/buildESModules.mjs +130 -0
- package/buildScripts/buildThemes.mjs +79 -64
- package/buildScripts/copyFolder.mjs +1 -1
- package/buildScripts/util/minifyHtml.mjs +26 -0
- package/buildScripts/webpack/production/webpack.config.appworker.mjs +27 -35
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/serverside/gridContainer/Viewport.mjs +1 -1
- package/examples/serverside/toolbarItems/Viewport.mjs +1 -1
- package/package.json +54 -51
- package/src/DefaultConfig.mjs +2 -2
- package/src/Main.mjs +1 -1
- package/src/code/LivePreview.mjs +4 -2
- package/src/container/Base.mjs +5 -3
- package/src/main/addon/Stylesheet.mjs +4 -3
- package/src/remotes/Api.mjs +5 -4
- package/src/state/Provider.mjs +8 -6
- package/src/worker/App.mjs +5 -5
- package/src/worker/Manager.mjs +10 -16
package/apps/ServiceWorker.mjs
CHANGED
package/apps/portal/index.html
CHANGED
@@ -14,9 +14,9 @@ class MainContainerStateProvider extends StateProvider {
|
|
14
14
|
*/
|
15
15
|
className: 'Portal.view.learn.MainContainerStateProvider',
|
16
16
|
/**
|
17
|
-
* @member {String} contentBasePath='
|
17
|
+
* @member {String} contentBasePath=Neo.config.basePath+'resources/data/deck/'
|
18
18
|
*/
|
19
|
-
contentBasePath: '
|
19
|
+
contentBasePath: Neo.config.basePath + 'resources/data/deck/',
|
20
20
|
/**
|
21
21
|
* @member {Object} data
|
22
22
|
*/
|
@@ -23,7 +23,7 @@ program
|
|
23
23
|
.name(programName)
|
24
24
|
.version(packageJson.version)
|
25
25
|
.option('-i, --info', 'print environment debug info')
|
26
|
-
.option('-e, --env <value>', '"all", "dev", "prod"')
|
26
|
+
.option('-e, --env <value>', '"all", "dev", "esm", "prod"')
|
27
27
|
.option('-l, --npminstall <value>', '"yes", "no"')
|
28
28
|
.option('-f, --framework')
|
29
29
|
.option('-n, --noquestions')
|
@@ -74,7 +74,7 @@ if (programOpts.info) {
|
|
74
74
|
type : 'list',
|
75
75
|
name : 'env',
|
76
76
|
message: 'Please choose the environment:',
|
77
|
-
choices: ['all', 'dev', 'prod'],
|
77
|
+
choices: ['all', 'dev', 'esm', 'prod'],
|
78
78
|
default: 'all'
|
79
79
|
});
|
80
80
|
}
|
@@ -129,17 +129,24 @@ if (programOpts.info) {
|
|
129
129
|
childProcess.status && process.exit(childProcess.status);
|
130
130
|
}
|
131
131
|
|
132
|
-
if (themes
|
132
|
+
if (themes === 'yes') {
|
133
133
|
childProcess = spawnSync('node', [`${neoPath}/buildScripts/buildThemes.mjs`].concat(cpArgs), cpOpts);
|
134
134
|
childProcess.status && process.exit(childProcess.status);
|
135
135
|
}
|
136
136
|
|
137
|
-
if (threads
|
138
|
-
|
139
|
-
|
137
|
+
if (threads === 'yes') {
|
138
|
+
if (env !== 'esm') {
|
139
|
+
childProcess = spawnSync('node', [`${webpackPath}/buildThreads.mjs`].concat(cpArgs), cpOpts);
|
140
|
+
childProcess.status && process.exit(childProcess.status);
|
141
|
+
}
|
142
|
+
|
143
|
+
if (env === 'all' || env === 'esm') {
|
144
|
+
childProcess = spawnSync('node', [`${neoPath}/buildScripts/buildESModules.mjs`], cpOpts);
|
145
|
+
childProcess.status && process.exit(childProcess.status);
|
146
|
+
}
|
140
147
|
}
|
141
148
|
|
142
|
-
if (parsedocs
|
149
|
+
if (parsedocs === 'yes') {
|
143
150
|
childProcess = spawnSync(npmCmd, ['run', 'generate-docs-json'], cpOpts);
|
144
151
|
childProcess.status && process.exit(childProcess.status);
|
145
152
|
}
|
@@ -0,0 +1,130 @@
|
|
1
|
+
import fs from 'fs-extra';
|
2
|
+
import path from 'path';
|
3
|
+
import {minify as minifyJs} from 'terser';
|
4
|
+
import {minifyHtml} from './util/minifyHtml.mjs';
|
5
|
+
import {fileURLToPath} from 'url';
|
6
|
+
|
7
|
+
const
|
8
|
+
__filename = fileURLToPath(import.meta.url),
|
9
|
+
__dirname = path.dirname(__filename),
|
10
|
+
inputDirectories = ['apps', 'docs', 'examples', 'src'],
|
11
|
+
outputBasePath = '../dist/esm/',
|
12
|
+
// Regex to find import statements with 'node_modules' in the path
|
13
|
+
// It captures the entire import statement (excluding the leading 'import') and the path itself.
|
14
|
+
regexImport = /(import(?:["'\s]*(?:[\w*{}\n\r\t, ]+)from\s*)?)(["'`])((?:(?!\2).)*node_modules(?:(?!\2).)*)\2/g;
|
15
|
+
|
16
|
+
async function minifyDirectory(inputDir, outputDir) {
|
17
|
+
if (fs.existsSync(inputDir)) {
|
18
|
+
fs.mkdirSync(outputDir, {recursive: true});
|
19
|
+
|
20
|
+
const dirents = fs.readdirSync(inputDir, {recursive: true, withFileTypes: true});
|
21
|
+
|
22
|
+
for (const dirent of dirents) {
|
23
|
+
if (dirent.isFile()) {
|
24
|
+
const
|
25
|
+
inputPath = path.join(dirent.path, dirent.name),
|
26
|
+
relativePath = path.relative(inputDir, inputPath),
|
27
|
+
outputPath = path.join(outputDir, relativePath),
|
28
|
+
content = fs.readFileSync(inputPath, 'utf8');
|
29
|
+
|
30
|
+
fs.mkdirSync(path.dirname(outputPath), {recursive: true});
|
31
|
+
|
32
|
+
try {
|
33
|
+
// Minify JSON files
|
34
|
+
if (dirent.name.endsWith('.json')) {
|
35
|
+
const jsonContent = JSON.parse(content);
|
36
|
+
|
37
|
+
if (dirent.name === 'neo-config.json') {
|
38
|
+
Object.assign(jsonContent, {
|
39
|
+
basePath : '../../' + jsonContent.basePath,
|
40
|
+
environment : 'dist/esm',
|
41
|
+
workerBasePath: jsonContent.basePath + 'src/worker/'
|
42
|
+
})
|
43
|
+
}
|
44
|
+
|
45
|
+
fs.writeFileSync(outputPath, JSON.stringify(jsonContent));
|
46
|
+
console.log(`Minified JSON: ${inputPath} -> ${outputPath}`);
|
47
|
+
}
|
48
|
+
// Minify HTML files
|
49
|
+
else if (dirent.name.endsWith('.html')) {
|
50
|
+
const minifiedContent = await minifyHtml(content);
|
51
|
+
|
52
|
+
fs.writeFileSync(outputPath, minifiedContent);
|
53
|
+
console.log(`Minified HTML: ${inputPath} -> ${outputPath}`);
|
54
|
+
}
|
55
|
+
// Minify JS files
|
56
|
+
else if (dirent.name.endsWith('.mjs')) {
|
57
|
+
let adjustedContent = content.replace(regexImport, (match, p1, p2, p3) => {
|
58
|
+
// p1 will be "import {marked} from " (or similar, including the 'import' keyword and everything up to the first quote)
|
59
|
+
// p2 will be the quote character (', ", or `)
|
60
|
+
// p3 will be the original path string (e.g., '../../../../node_modules/marked/lib/marked.esm.js')
|
61
|
+
|
62
|
+
const newPath = '../../' + p3; // Prepend 2 levels up
|
63
|
+
|
64
|
+
// Reconstruct the import statement with the new path
|
65
|
+
return p1 + p2 + newPath + p2;
|
66
|
+
});
|
67
|
+
|
68
|
+
const result = await minifyJs(adjustedContent, {
|
69
|
+
module: true,
|
70
|
+
compress: {
|
71
|
+
dead_code: true
|
72
|
+
},
|
73
|
+
mangle: {
|
74
|
+
toplevel: true
|
75
|
+
}
|
76
|
+
});
|
77
|
+
|
78
|
+
fs.writeFileSync(outputPath, result.code);
|
79
|
+
console.log(`Minified JS: ${inputPath} -> ${outputPath}`);
|
80
|
+
}
|
81
|
+
} catch (e) {
|
82
|
+
console.error(`Error minifying ${inputPath}:`, e);
|
83
|
+
}
|
84
|
+
}
|
85
|
+
// Copy resources folders
|
86
|
+
else if (dirent.name === 'resources') {
|
87
|
+
const
|
88
|
+
inputPath = path.join(dirent.path, dirent.name),
|
89
|
+
relativePath = path.relative(inputDir, inputPath),
|
90
|
+
outputPath = path.join(outputDir, relativePath);
|
91
|
+
|
92
|
+
fs.mkdirSync(path.dirname(outputPath), {recursive: true});
|
93
|
+
|
94
|
+
fs.copySync(inputPath, outputPath);
|
95
|
+
|
96
|
+
// Minify all JSON files inside the copied folder
|
97
|
+
const resourcesEntries = fs.readdirSync(outputPath, {recursive: true, withFileTypes: true});
|
98
|
+
|
99
|
+
for (const resource of resourcesEntries) {
|
100
|
+
if (resource.isFile()) {
|
101
|
+
if (resource.name.endsWith('.json')) {
|
102
|
+
const
|
103
|
+
resourcePath = path.join(resource.path, resource.name),
|
104
|
+
content = fs.readFileSync(resourcePath, 'utf8');
|
105
|
+
|
106
|
+
fs.writeFileSync(resourcePath, JSON.stringify(JSON.parse(content)));
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
const promises = [];
|
116
|
+
|
117
|
+
// Execute the minification
|
118
|
+
inputDirectories.forEach(folder => {
|
119
|
+
promises.push(minifyDirectory(path.resolve(__dirname, '../' + folder), path.resolve(__dirname, outputBasePath, folder))
|
120
|
+
.catch(err => {
|
121
|
+
console.error('Minification failed:', err);
|
122
|
+
process.exit(1) // Exit with error code
|
123
|
+
})
|
124
|
+
);
|
125
|
+
});
|
126
|
+
|
127
|
+
Promise.all(promises).then(() => {
|
128
|
+
console.log('Minification complete.');
|
129
|
+
process.exit()
|
130
|
+
});
|
@@ -34,7 +34,7 @@ program
|
|
34
34
|
.name(programName)
|
35
35
|
.version(packageJson.version)
|
36
36
|
.option('-i, --info', 'print environment debug info')
|
37
|
-
.option('-e, --env <value>', '"all", "dev", "prod"')
|
37
|
+
.option('-e, --env <value>', '"all", "dev", "esm", "prod"')
|
38
38
|
.option('-f, --framework')
|
39
39
|
.option('-n, --noquestions')
|
40
40
|
.option('-t, --themes <value>', ["all", ...themeFolders].join(", "))
|
@@ -83,19 +83,19 @@ if (programOpts.info) {
|
|
83
83
|
type : 'list',
|
84
84
|
name : 'env',
|
85
85
|
message: 'Please choose the environment:',
|
86
|
-
choices: ['all', 'dev', 'prod'],
|
86
|
+
choices: ['all', 'dev', 'esm', 'prod'],
|
87
87
|
default: 'all'
|
88
88
|
});
|
89
89
|
}
|
90
90
|
}
|
91
91
|
|
92
|
-
inquirer.prompt(questions).then(answers => {
|
92
|
+
inquirer.prompt(questions).then(async answers => {
|
93
93
|
const env = answers.env || programOpts.env || 'all',
|
94
94
|
themes = answers.themes || programOpts.themes || 'all',
|
95
95
|
insideNeo = programOpts.framework || false,
|
96
96
|
startDate = new Date(),
|
97
|
-
fileCount = {development: 0, production: 0},
|
98
|
-
totalFiles = {development: 0, production: 0};
|
97
|
+
fileCount = {development: 0, esm: 0, production: 0},
|
98
|
+
totalFiles = {development: 0, esm: 0, production: 0};
|
99
99
|
|
100
100
|
let themeMap;
|
101
101
|
|
@@ -124,14 +124,14 @@ if (programOpts.info) {
|
|
124
124
|
* @param {String} p
|
125
125
|
* @param {String} mode development or production
|
126
126
|
*/
|
127
|
-
function buildEnv(p, mode) {
|
128
|
-
parseScssFiles(getAllScssFiles(path.join(p, 'src')), mode, 'src');
|
127
|
+
async function buildEnv(p, mode) {
|
128
|
+
await parseScssFiles(getAllScssFiles(path.join(p, 'src')), mode, 'src');
|
129
129
|
|
130
|
-
|
130
|
+
for (const themeFolder of themeFolders) {
|
131
131
|
if (themes === 'all' || themes === themeFolder) {
|
132
|
-
parseScssFiles(getAllScssFiles(path.join(p, themeFolder)), mode, themeFolder);
|
132
|
+
await parseScssFiles(getAllScssFiles(path.join(p, themeFolder)), mode, themeFolder);
|
133
133
|
}
|
134
|
-
}
|
134
|
+
}
|
135
135
|
}
|
136
136
|
|
137
137
|
/**
|
@@ -247,17 +247,17 @@ if (programOpts.info) {
|
|
247
247
|
* @param {String} mode development or production
|
248
248
|
* @param {String} target src or a theme
|
249
249
|
*/
|
250
|
-
function parseScssFiles(files, mode, target) {
|
251
|
-
let devMode = mode === 'development'
|
252
|
-
map;
|
250
|
+
async function parseScssFiles(files, mode, target) {
|
251
|
+
let devMode = mode === 'development';
|
253
252
|
|
254
253
|
totalFiles[mode] += files.length;
|
255
254
|
|
256
|
-
|
255
|
+
for (const file of files) {
|
257
256
|
addItemToThemeMap(file, target);
|
258
257
|
|
259
258
|
let folderPath = path.resolve(cwd, `dist/${mode}/css/${target}/${file.relativePath}`),
|
260
|
-
destPath = path.resolve(folderPath, `${file.name}.css`)
|
259
|
+
destPath = path.resolve(folderPath, `${file.name}.css`),
|
260
|
+
map;
|
261
261
|
|
262
262
|
let result = sass.compile(file.path, {
|
263
263
|
outFile : destPath,
|
@@ -267,71 +267,71 @@ if (programOpts.info) {
|
|
267
267
|
|
268
268
|
const plugins = [autoprefixer];
|
269
269
|
|
270
|
-
if (mode === 'production') {
|
271
|
-
plugins.push(cssnano)
|
270
|
+
if (mode === 'esm' || mode === 'production') {
|
271
|
+
plugins.push(cssnano) // CSSNano works async only
|
272
272
|
}
|
273
273
|
|
274
274
|
map = result.sourceMap;
|
275
275
|
|
276
|
-
postcss(plugins).process(result.css, {
|
276
|
+
const postcssResult = await postcss(plugins).process(result.css, {
|
277
277
|
from: file.path,
|
278
278
|
to : destPath,
|
279
279
|
map : !devMode ? null : {
|
280
280
|
inline: false,
|
281
281
|
prev : map && JSON.stringify(map)
|
282
282
|
}
|
283
|
-
})
|
284
|
-
fs.mkdirpSync(folderPath);
|
285
|
-
fileCount[mode]++;
|
283
|
+
});
|
286
284
|
|
287
|
-
|
288
|
-
|
285
|
+
fs.mkdirpSync(folderPath);
|
286
|
+
fileCount[mode]++;
|
289
287
|
|
290
|
-
|
288
|
+
let currentFileNumber = fileCount.development + fileCount.esm + fileCount.production,
|
289
|
+
processTime = (Math.round((new Date - startDate) * 100) / 100000).toFixed(2);
|
291
290
|
|
292
|
-
|
293
|
-
destPath,
|
294
|
-
map ?
|
295
|
-
`${postcssResult.css}\n\n/*# sourceMappingURL=${path.relative(path.dirname(destPath), postcssResult.opts.to + '.map')} */` :
|
296
|
-
postcssResult.css,
|
297
|
-
() => true
|
298
|
-
);
|
291
|
+
map = postcssResult.map;
|
299
292
|
|
300
|
-
|
301
|
-
let mapString = map.toString(),
|
302
|
-
jsonMap = JSON.parse(mapString),
|
303
|
-
sources = jsonMap.sources;
|
304
|
-
|
305
|
-
// Somehow files contain both: a relative & an absolute file url
|
306
|
-
// We only want to keep the relative ones.
|
307
|
-
[...sources].forEach((item, index) => {
|
308
|
-
if (!item.startsWith('../')) {
|
309
|
-
sources.splice(index, 1);
|
310
|
-
}
|
311
|
-
});
|
293
|
+
console.log('Writing file:', currentFileNumber, chalk.blue(`${processTime}s`), destPath);
|
312
294
|
|
313
|
-
|
295
|
+
fs.writeFileSync(
|
296
|
+
destPath,
|
297
|
+
map ?
|
298
|
+
`${postcssResult.css}\n\n/*# sourceMappingURL=${path.relative(path.dirname(destPath), postcssResult.opts.to + '.map')} */` :
|
299
|
+
postcssResult.css,
|
300
|
+
() => true
|
301
|
+
);
|
314
302
|
|
315
|
-
|
316
|
-
|
303
|
+
if (map) {
|
304
|
+
let mapString = map.toString(),
|
305
|
+
jsonMap = JSON.parse(mapString),
|
306
|
+
sources = jsonMap.sources;
|
317
307
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
308
|
+
// Somehow files contain both: a relative & an absolute file url
|
309
|
+
// We only want to keep the relative ones.
|
310
|
+
[...sources].forEach((item, index) => {
|
311
|
+
if (!item.startsWith('../')) {
|
312
|
+
sources.splice(index, 1);
|
313
|
+
}
|
314
|
+
});
|
323
315
|
|
324
|
-
|
325
|
-
recursive: true
|
326
|
-
});
|
316
|
+
map = JSON.stringify(jsonMap);
|
327
317
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
318
|
+
fs.writeFileSync(postcssResult.opts.to + '.map', map);
|
319
|
+
}
|
320
|
+
|
321
|
+
if (fileCount[mode] === totalFiles[mode]) {
|
322
|
+
fs.writeFileSync(
|
323
|
+
path.resolve(cwd, themeMapFile),
|
324
|
+
JSON.stringify(themeMap, null, 0)
|
325
|
+
);
|
326
|
+
|
327
|
+
fs.mkdirpSync(path.join(cwd, '/dist/', mode, '/resources'), {recursive: true});
|
328
|
+
|
329
|
+
fs.writeFileSync(
|
330
|
+
path.join(cwd, '/dist/', mode, themeMapFile),
|
331
|
+
JSON.stringify(themeMap, null, 0)
|
332
|
+
);
|
333
|
+
}
|
334
|
+
}
|
335
335
|
}
|
336
336
|
|
337
337
|
themeMap = getThemeMap(themeMapFile);
|
@@ -339,13 +339,28 @@ if (programOpts.info) {
|
|
339
339
|
// dist/development
|
340
340
|
if (env === 'all' || env === 'dev') {
|
341
341
|
console.log(chalk.blue(`${programName} starting dist/development`));
|
342
|
-
buildEnv(scssPath, 'development');
|
342
|
+
await buildEnv(scssPath, 'development');
|
343
|
+
}
|
344
|
+
|
345
|
+
// dist/esm
|
346
|
+
if (env === 'all' || env === 'esm') {
|
347
|
+
console.log(chalk.blue(`${programName} starting dist/esm`));
|
348
|
+
await buildEnv(scssPath, 'esm');
|
343
349
|
}
|
344
350
|
|
345
351
|
// dist/production
|
346
|
-
if (env === '
|
352
|
+
if (env === 'prod') {
|
347
353
|
console.log(chalk.blue(`${programName} starting dist/production`));
|
348
|
-
buildEnv(scssPath, 'production');
|
354
|
+
await buildEnv(scssPath, 'production');
|
355
|
+
} else if (env === 'all') {
|
356
|
+
// dist/esm & dist/production contain the same output, so we can just copy it over.
|
357
|
+
const cssPath = path.join(cwd, '/dist/production/css');
|
358
|
+
|
359
|
+
fs.mkdirpSync(cssPath, {recursive: true});
|
360
|
+
fs.mkdirpSync(path.join(cwd, '/dist/production/resources'), {recursive: true});
|
361
|
+
|
362
|
+
fs.copySync(path.join(cwd, '/dist/esm/css'), cssPath);
|
363
|
+
fs.copySync(path.join(cwd, '/dist/esm/resources/theme-map.json'), path.join(cwd, '/dist/production/resources/theme-map.json'));
|
349
364
|
}
|
350
365
|
});
|
351
366
|
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import {minify} from 'html-minifier-terser';
|
2
|
+
|
3
|
+
const
|
4
|
+
regexBlankAfterColon = /: /g,
|
5
|
+
regexBlankAfterComma = /, /g,
|
6
|
+
regexIndexNodeModules = /node_modules/g;
|
7
|
+
|
8
|
+
export async function minifyHtml(content) {
|
9
|
+
const minifiedContent = await minify(content, {
|
10
|
+
collapseWhitespace : true,
|
11
|
+
minifyCSS : true,
|
12
|
+
minifyJS : true,
|
13
|
+
processScripts : ['application/ld+json'],
|
14
|
+
removeComments : true,
|
15
|
+
removeEmptyAttributes : true,
|
16
|
+
removeRedundantAttributes : true,
|
17
|
+
removeScriptTypeAttributes : true,
|
18
|
+
removeStyleLinkTypeAttributes: true,
|
19
|
+
useShortDoctype : true
|
20
|
+
});
|
21
|
+
|
22
|
+
return minifiedContent
|
23
|
+
.replace(regexBlankAfterColon, ':')
|
24
|
+
.replace(regexBlankAfterComma, ',')
|
25
|
+
.replace(regexIndexNodeModules, '../../node_modules')
|
26
|
+
}
|
@@ -1,21 +1,19 @@
|
|
1
|
-
import fs
|
2
|
-
import path
|
3
|
-
import {spawnSync}
|
4
|
-
import
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
regexTrimEnd = /\s+$/gm,
|
18
|
-
regexTrimStart = /^\s+/gm;
|
1
|
+
import fs from 'fs-extra';
|
2
|
+
import path from 'path';
|
3
|
+
import {spawnSync} from 'child_process';
|
4
|
+
import {minifyHtml} from '../../util/minifyHtml.mjs';
|
5
|
+
import webpack from 'webpack';
|
6
|
+
|
7
|
+
const
|
8
|
+
cwd = process.cwd(),
|
9
|
+
cpOpts = {env: process.env, cwd: cwd, stdio: 'inherit', shell: true},
|
10
|
+
requireJson = path => JSON.parse(fs.readFileSync((path))),
|
11
|
+
packageJson = requireJson(path.resolve(cwd, 'package.json')),
|
12
|
+
neoPath = packageJson.name.includes('neo.mjs') ? './' : './node_modules/neo.mjs/',
|
13
|
+
buildTarget = requireJson(path.resolve(neoPath, 'buildScripts/webpack/production/buildTarget.json')),
|
14
|
+
filenameConfig = requireJson(path.resolve(neoPath, 'buildScripts/webpack/json/build.json')),
|
15
|
+
plugins = [],
|
16
|
+
regexTopLevel = /\.\.\//g;
|
19
17
|
|
20
18
|
let contextAdjusted = false,
|
21
19
|
examplesPath;
|
@@ -24,7 +22,7 @@ if (!buildTarget.folder) {
|
|
24
22
|
buildTarget.folder = 'dist/production';
|
25
23
|
}
|
26
24
|
|
27
|
-
export default env
|
25
|
+
export default async function(env) {
|
28
26
|
let apps = [],
|
29
27
|
examples = [],
|
30
28
|
insideNeo = env.insideNeo == 'true',
|
@@ -59,7 +57,7 @@ export default env => {
|
|
59
57
|
}
|
60
58
|
};
|
61
59
|
|
62
|
-
const createStartingPoint = (key, folder) => {
|
60
|
+
const createStartingPoint = async (key, folder) => {
|
63
61
|
let basePath = '',
|
64
62
|
workerBasePath = '',
|
65
63
|
treeLevel = key.replace('.', '/').split('/').length + (key === 'Docs' ? 2 : 3),
|
@@ -105,15 +103,9 @@ export default env => {
|
|
105
103
|
// index.html
|
106
104
|
inputPath = path.resolve(cwd, folder, lAppName, 'index.html');
|
107
105
|
outputPath = path.resolve(cwd, buildTarget.folder, folder, lAppName, 'index.html');
|
106
|
+
content = await minifyHtml(fs.readFileSync(inputPath, 'utf-8'));
|
108
107
|
|
109
|
-
|
110
|
-
.replace(regexIndexNodeModules, '../../node_modules')
|
111
|
-
.replace(regexTrimStart, '')
|
112
|
-
.replace(regexTrimEnd, '')
|
113
|
-
.replace(', ', ',')
|
114
|
-
.replace(regexLineBreak, '');
|
115
|
-
|
116
|
-
fs.writeFileSync(outputPath, content);
|
108
|
+
fs.writeFileSync(outputPath, content)
|
117
109
|
};
|
118
110
|
|
119
111
|
const isFile = fileName => fs.lstatSync(fileName).isFile();
|
@@ -136,13 +128,13 @@ export default env => {
|
|
136
128
|
|
137
129
|
parseFolder(apps, path.join(cwd, 'apps'), 0, '');
|
138
130
|
|
139
|
-
|
131
|
+
for (const key of apps) {
|
140
132
|
copyResources(path.join('apps', key, '/resources'));
|
141
|
-
createStartingPoint(key.substr(1), 'apps');
|
142
|
-
}
|
133
|
+
await createStartingPoint(key.substr(1), 'apps');
|
134
|
+
}
|
143
135
|
|
144
136
|
if (fs.existsSync(path.join(cwd, 'docs'))) {
|
145
|
-
createStartingPoint('Docs', '');
|
137
|
+
await createStartingPoint('Docs', '');
|
146
138
|
}
|
147
139
|
|
148
140
|
examplesPath = path.join(cwd, 'examples');
|
@@ -150,10 +142,10 @@ export default env => {
|
|
150
142
|
if (fs.existsSync(examplesPath)) {
|
151
143
|
parseFolder(examples, examplesPath, 0, '');
|
152
144
|
|
153
|
-
|
145
|
+
for (const key of examples) {
|
154
146
|
copyResources(path.join('examples', key, '/resources'));
|
155
|
-
createStartingPoint(key.substr(1), 'examples');
|
156
|
-
}
|
147
|
+
await createStartingPoint(key.substr(1), 'examples');
|
148
|
+
}
|
157
149
|
}
|
158
150
|
|
159
151
|
return {
|
@@ -31,7 +31,7 @@ class Viewport extends BaseViewport {
|
|
31
31
|
async onLoadGridContainerButtonClick(data) {
|
32
32
|
data.component.disabled = true;
|
33
33
|
|
34
|
-
let items = await this.loadItems('../../examples/serverside/gridContainer/resources/data/grid-container.json');
|
34
|
+
let items = await this.loadItems({url: '../../examples/serverside/gridContainer/resources/data/grid-container.json'});
|
35
35
|
|
36
36
|
this.getReference('container').add(items)
|
37
37
|
}
|
@@ -30,7 +30,7 @@ class Viewport extends BaseViewport {
|
|
30
30
|
async onLoadItemsButtonClick(data) {
|
31
31
|
data.component.disabled = true;
|
32
32
|
|
33
|
-
let items = await this.loadItems('../../examples/serverside/toolbarItems/resources/data/toolbar-items.json');
|
33
|
+
let items = await this.loadItems({url: '../../examples/serverside/toolbarItems/resources/data/toolbar-items.json'});
|
34
34
|
|
35
35
|
this.getReference('toolbar').add(items)
|
36
36
|
}
|
package/package.json
CHANGED
@@ -1,33 +1,34 @@
|
|
1
1
|
{
|
2
|
-
"name": "neo.mjs",
|
3
|
-
"version": "9.
|
4
|
-
"description": "The webworkers driven UI framework",
|
5
|
-
"type": "module",
|
6
|
-
"repository": {
|
2
|
+
"name" : "neo.mjs",
|
3
|
+
"version" : "9.6.1",
|
4
|
+
"description" : "The webworkers driven UI framework",
|
5
|
+
"type" : "module",
|
6
|
+
"repository" : {
|
7
7
|
"type": "git",
|
8
|
-
"url": "https://github.com/neomjs/neo.git"
|
8
|
+
"url" : "https://github.com/neomjs/neo.git"
|
9
9
|
},
|
10
|
-
"bin": {
|
10
|
+
"bin" : {
|
11
11
|
"neo-cc": "./buildScripts/createClass.mjs"
|
12
12
|
},
|
13
|
-
"scripts": {
|
14
|
-
"add-config": "node ./buildScripts/addConfig.mjs",
|
15
|
-
"build-all": "node ./buildScripts/buildAll.mjs -f -n",
|
16
|
-
"build-all-questions": "node ./buildScripts/buildAll.mjs -f",
|
17
|
-
"build-
|
18
|
-
"build-
|
19
|
-
"
|
20
|
-
"
|
21
|
-
"create-app
|
22
|
-
"create-
|
23
|
-
"create-
|
24
|
-
"
|
13
|
+
"scripts" : {
|
14
|
+
"add-config" : "node ./buildScripts/addConfig.mjs",
|
15
|
+
"build-all" : "node ./buildScripts/buildAll.mjs -f -n",
|
16
|
+
"build-all-questions" : "node ./buildScripts/buildAll.mjs -f",
|
17
|
+
"build-es-modules" : "node ./buildScripts/buildESModules.mjs",
|
18
|
+
"build-themes" : "node ./buildScripts/buildThemes.mjs -f",
|
19
|
+
"build-threads" : "node ./buildScripts/webpack/buildThreads.mjs -f",
|
20
|
+
"convert-design-tokens" : "node ./buildScripts/convertDesignTokens.mjs",
|
21
|
+
"create-app" : "node ./buildScripts/createApp.mjs",
|
22
|
+
"create-app-minimal" : "node ./buildScripts/createAppMinimal.mjs",
|
23
|
+
"create-class" : "node ./buildScripts/createClass.mjs",
|
24
|
+
"create-component" : "node ./buildScripts/createComponent.mjs",
|
25
|
+
"generate-docs-json" : "node ./buildScripts/docs/jsdocx.mjs",
|
25
26
|
"inject-package-version": "node ./buildScripts/injectPackageVersion.mjs",
|
26
|
-
"server-start": "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open",
|
27
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
28
|
-
"watch-themes": "node ./buildScripts/watchThemes.mjs"
|
27
|
+
"server-start" : "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open",
|
28
|
+
"test" : "echo \"Error: no test specified\" && exit 1",
|
29
|
+
"watch-themes" : "node ./buildScripts/watchThemes.mjs"
|
29
30
|
},
|
30
|
-
"keywords": [
|
31
|
+
"keywords" : [
|
31
32
|
"javascript",
|
32
33
|
"frontend",
|
33
34
|
"framework",
|
@@ -40,39 +41,41 @@
|
|
40
41
|
"react-alternative",
|
41
42
|
"angular-alternative"
|
42
43
|
],
|
43
|
-
"author": "Tobias Uhlig",
|
44
|
-
"license": "MIT",
|
45
|
-
"bugs": {
|
44
|
+
"author" : "Tobias Uhlig",
|
45
|
+
"license" : "MIT",
|
46
|
+
"bugs" : {
|
46
47
|
"url": "https://github.com/neomjs/neo/issues"
|
47
48
|
},
|
48
|
-
"homepage": "https://neomjs.com/",
|
49
|
+
"homepage" : "https://neomjs.com/",
|
49
50
|
"devDependencies": {
|
50
51
|
"@fortawesome/fontawesome-free": "^6.7.2",
|
51
|
-
"autoprefixer": "^10.4.21",
|
52
|
-
"chalk": "^5.4.1",
|
53
|
-
"clean-webpack-plugin": "^4.0.0",
|
54
|
-
"commander": "^14.0.0",
|
55
|
-
"cssnano": "^7.0.7",
|
56
|
-
"envinfo": "^7.14.0",
|
57
|
-
"fs-extra": "^11.3.0",
|
58
|
-
"highlightjs-line-numbers.js": "^2.9.0",
|
59
|
-
"
|
60
|
-
"
|
61
|
-
"
|
62
|
-
"
|
63
|
-
"neo-jsdoc
|
64
|
-
"
|
65
|
-
"
|
66
|
-
"
|
67
|
-
"
|
68
|
-
"
|
69
|
-
"
|
70
|
-
"webpack
|
71
|
-
"webpack-
|
72
|
-
"webpack-
|
52
|
+
"autoprefixer" : "^10.4.21",
|
53
|
+
"chalk" : "^5.4.1",
|
54
|
+
"clean-webpack-plugin" : "^4.0.0",
|
55
|
+
"commander" : "^14.0.0",
|
56
|
+
"cssnano" : "^7.0.7",
|
57
|
+
"envinfo" : "^7.14.0",
|
58
|
+
"fs-extra" : "^11.3.0",
|
59
|
+
"highlightjs-line-numbers.js" : "^2.9.0",
|
60
|
+
"html-minifier-terser" : "^7.2.0",
|
61
|
+
"inquirer" : "^12.6.3",
|
62
|
+
"marked" : "^15.0.12",
|
63
|
+
"monaco-editor" : "0.50.0",
|
64
|
+
"neo-jsdoc" : "1.0.1",
|
65
|
+
"neo-jsdoc-x" : "1.0.5",
|
66
|
+
"postcss" : "^8.5.4",
|
67
|
+
"sass" : "^1.89.1",
|
68
|
+
"siesta-lite" : "5.5.2",
|
69
|
+
"terser" : "^5.40.0",
|
70
|
+
"url" : "^0.11.4",
|
71
|
+
"webpack" : "^5.99.9",
|
72
|
+
"webpack-cli" : "^6.0.1",
|
73
|
+
"webpack-dev-server" : "^5.2.1",
|
74
|
+
"webpack-hook-plugin" : "^1.0.7",
|
75
|
+
"webpack-node-externals" : "^3.0.0"
|
73
76
|
},
|
74
|
-
"funding": {
|
77
|
+
"funding" : {
|
75
78
|
"type": "GitHub Sponsors",
|
76
|
-
"url": "https://github.com/sponsors/tobiu"
|
79
|
+
"url" : "https://github.com/sponsors/tobiu"
|
77
80
|
}
|
78
81
|
}
|
package/src/DefaultConfig.mjs
CHANGED
@@ -263,12 +263,12 @@ const DefaultConfig = {
|
|
263
263
|
useVdomWorker: true,
|
264
264
|
/**
|
265
265
|
* buildScripts/injectPackageVersion.mjs will update this value
|
266
|
-
* @default '9.
|
266
|
+
* @default '9.6.1'
|
267
267
|
* @memberOf! module:Neo
|
268
268
|
* @name config.version
|
269
269
|
* @type String
|
270
270
|
*/
|
271
|
-
version: '9.
|
271
|
+
version: '9.6.1'
|
272
272
|
};
|
273
273
|
|
274
274
|
Object.assign(DefaultConfig, {
|
package/src/Main.mjs
CHANGED
@@ -253,7 +253,7 @@ class Main extends core.Base {
|
|
253
253
|
|
254
254
|
// we need different publicPath values for the main thread inside the webpack based dist envs,
|
255
255
|
// depending on the hierarchy level of the app entry point
|
256
|
-
if (config.environment
|
256
|
+
if (config.environment === 'dist/development' || config.environment === 'dist/production') {
|
257
257
|
__webpack_require__.p = config.basePath.substring(6)
|
258
258
|
}
|
259
259
|
|
package/src/code/LivePreview.mjs
CHANGED
@@ -223,11 +223,13 @@ class LivePreview extends Container {
|
|
223
223
|
}
|
224
224
|
|
225
225
|
let me = this,
|
226
|
+
{config} = Neo,
|
226
227
|
container = me.getPreviewContainer(),
|
228
|
+
hasJsModules = config.environment === 'development' || config.environment === 'dist/esm',
|
227
229
|
source = me.editorValue || me.value,
|
230
|
+
className = me.findLastClassName(source),
|
228
231
|
cleanLines = [],
|
229
232
|
moduleNameAndPath = [],
|
230
|
-
className = me.findLastClassName(source),
|
231
233
|
params = [],
|
232
234
|
vars = [],
|
233
235
|
codeString, promises;
|
@@ -240,7 +242,7 @@ class LivePreview extends Container {
|
|
240
242
|
path = importMatch[2],
|
241
243
|
index;
|
242
244
|
|
243
|
-
if (
|
245
|
+
if (!hasJsModules) {
|
244
246
|
index = path.lastIndexOf('../');
|
245
247
|
|
246
248
|
if (index === 0) {
|
package/src/container/Base.mjs
CHANGED
@@ -586,11 +586,13 @@ class Container extends Component {
|
|
586
586
|
* {"modules": [], "items": []}
|
587
587
|
* See: https://github.com/neomjs/neo/blob/dev/examples/serverside/gridContainer/resources/data/grid-container.json
|
588
588
|
* It is important to add modules which are not already imported inside your app yet.
|
589
|
-
* @param {
|
589
|
+
* @param {Object} data
|
590
|
+
* @param {Object} [data.options={}]
|
591
|
+
* @param {String} data.url
|
590
592
|
* @returns {Promise<Object[]>}
|
591
593
|
*/
|
592
|
-
async loadItems(url) {
|
593
|
-
let response = await fetch(url),
|
594
|
+
async loadItems({options={}, url}) {
|
595
|
+
let response = await fetch(url, options),
|
594
596
|
remoteData = await response.json();
|
595
597
|
|
596
598
|
if (remoteData.modules?.length > 0) {
|
@@ -43,13 +43,14 @@ class Stylesheet extends Base {
|
|
43
43
|
super.construct(config);
|
44
44
|
|
45
45
|
let neoConfig = Neo.config,
|
46
|
+
env = neoConfig.environment,
|
46
47
|
faPath;
|
47
48
|
|
48
49
|
if (neoConfig.useFontAwesome) {
|
49
|
-
if (
|
50
|
+
if (env === 'development' || env === 'dist/esm') {
|
50
51
|
faPath = neoConfig.basePath + 'node_modules/@fortawesome/fontawesome-free/css/all.min.css'
|
51
52
|
} else {
|
52
|
-
faPath = neoConfig.basePath.
|
53
|
+
faPath = neoConfig.basePath.substring(6) + 'resources/fontawesome-free/css/all.min.css'
|
53
54
|
}
|
54
55
|
|
55
56
|
this.createStyleSheet(null, null, faPath)
|
@@ -68,7 +69,7 @@ class Stylesheet extends Base {
|
|
68
69
|
{themes} = config,
|
69
70
|
folders = ['src', ...themes],
|
70
71
|
env = config.environment,
|
71
|
-
path
|
72
|
+
path = env.startsWith('dist/') ? '' : config.appPath.includes('docs') ? `../dist/${env}/` : `../../dist/${env}/`,
|
72
73
|
rootPath = config.basePath.substring(6);
|
73
74
|
|
74
75
|
document.body.classList.add(themes[0]);
|
package/src/remotes/Api.mjs
CHANGED
@@ -39,15 +39,16 @@ class Api extends Base {
|
|
39
39
|
*
|
40
40
|
*/
|
41
41
|
load() {
|
42
|
-
let {config}
|
43
|
-
|
42
|
+
let {config} = Neo,
|
43
|
+
hasJsModules = config.environment === 'development' || config.environment === 'dist/esm',
|
44
|
+
path = config.remotesApiUrl;
|
44
45
|
|
45
|
-
//
|
46
|
+
// Relative paths need a special treatment
|
46
47
|
if (!path.includes('http')) {
|
47
48
|
path = config.appPath.split('/');
|
48
49
|
path.pop();
|
49
50
|
path = `${path.join('/')}/${config.remotesApiUrl}`;
|
50
|
-
path = (
|
51
|
+
path = (hasJsModules ? '../../' : './') + path
|
51
52
|
}
|
52
53
|
|
53
54
|
fetch(path)
|
package/src/state/Provider.mjs
CHANGED
@@ -391,20 +391,22 @@ class Provider extends Base {
|
|
391
391
|
* @param {String} value
|
392
392
|
*/
|
393
393
|
getFormatterVariables(value) {
|
394
|
+
let {environment} = Neo.config;
|
395
|
+
|
394
396
|
if (Neo.isFunction(value)) {
|
395
397
|
value = value.toString()
|
396
398
|
}
|
397
399
|
|
398
|
-
if (
|
399
|
-
//
|
400
|
-
//
|
400
|
+
if (environment === 'dist/esm' || environment === 'dist/production') {
|
401
|
+
// See: https://github.com/neomjs/neo/issues/2371
|
402
|
+
// Inside dist/esm & dist/prod the formatter:
|
401
403
|
// data => DateUtil.convertToyyyymmdd(data.currentDate)
|
402
404
|
// will get minified to:
|
403
405
|
// e=>s.Z.convertToyyyymmdd(e.currentDate)
|
404
|
-
//
|
405
|
-
//
|
406
|
+
// The new strategy: find the first variable name => "e"
|
407
|
+
// Replace it with "data":
|
406
408
|
// data=>s.Z.convertToyyyymmdd(data.currentDate)
|
407
|
-
//
|
409
|
+
// From there we can use the dev mode regex again.
|
408
410
|
|
409
411
|
let dataName = value.match(variableNameRegex)[0],
|
410
412
|
variableRegExp = new RegExp(`(^|[^\\w.])(${dataName})(?!\\w)`, 'g');
|
package/src/worker/App.mjs
CHANGED
@@ -300,7 +300,7 @@ class App extends Base {
|
|
300
300
|
|
301
301
|
return import(
|
302
302
|
/* webpackInclude: /(?:\/|\\)app.mjs$/ */
|
303
|
-
/* webpackExclude: /(?:\/|\\)node_modules/ */
|
303
|
+
/* webpackExclude: /(?:\/|\\)(dist|node_modules)/ */
|
304
304
|
/* webpackMode: "lazy" */
|
305
305
|
`../../${path}.mjs`
|
306
306
|
)
|
@@ -433,15 +433,15 @@ class App extends Base {
|
|
433
433
|
onRegisterNeoConfig(msg) {
|
434
434
|
super.onRegisterNeoConfig(msg);
|
435
435
|
|
436
|
-
let config = Neo
|
437
|
-
{data}
|
438
|
-
url
|
436
|
+
let {config} = Neo,
|
437
|
+
{data} = msg,
|
438
|
+
url = 'resources/theme-map.json';
|
439
439
|
|
440
440
|
Neo.windowConfigs = Neo.windowConfigs || {};
|
441
441
|
|
442
442
|
Neo.windowConfigs[data.windowId] = data;
|
443
443
|
|
444
|
-
if (config.environment === 'development') {
|
444
|
+
if (config.environment === 'development' || config.environment === 'dist/esm') {
|
445
445
|
url = `../../${url}`
|
446
446
|
}
|
447
447
|
|
package/src/worker/Manager.mjs
CHANGED
@@ -5,8 +5,8 @@ import Message from './Message.mjs';
|
|
5
5
|
import Observable from '../core/Observable.mjs';
|
6
6
|
import RemoteMethodAccess from './mixin/RemoteMethodAccess.mjs';
|
7
7
|
|
8
|
-
const NeoConfig
|
9
|
-
|
8
|
+
const NeoConfig = Neo.config,
|
9
|
+
hasJsModules = NeoConfig.environment === 'development' || NeoConfig.environment === 'dist/esm';
|
10
10
|
|
11
11
|
// Using ?. since SWs do not exist for http (only https)
|
12
12
|
navigator.serviceWorker?.addEventListener('controllerchange', function() {
|
@@ -42,12 +42,6 @@ class Manager extends Base {
|
|
42
42
|
* @protected
|
43
43
|
*/
|
44
44
|
appNames: [],
|
45
|
-
/**
|
46
|
-
* The base path for the worker file URLs, can e.g. get set inside the index.html.
|
47
|
-
* @member {String|null} basePath=Neo.config.workerBasePath || 'worker/'
|
48
|
-
* @protected
|
49
|
-
*/
|
50
|
-
basePath: NeoConfig.workerBasePath || 'worker/',
|
51
45
|
/**
|
52
46
|
* @member {Number} constructedThreads=0
|
53
47
|
* @protected
|
@@ -89,19 +83,19 @@ class Manager extends Base {
|
|
89
83
|
*/
|
90
84
|
workers: {
|
91
85
|
app: {
|
92
|
-
fileName:
|
86
|
+
fileName: hasJsModules ? 'App.mjs' : 'appworker.js'
|
93
87
|
},
|
94
88
|
canvas: {
|
95
|
-
fileName:
|
89
|
+
fileName: hasJsModules ? 'Canvas.mjs' : 'canvasworker.js'
|
96
90
|
},
|
97
91
|
data: {
|
98
|
-
fileName:
|
92
|
+
fileName: hasJsModules ? 'Data.mjs' : 'dataworker.js'
|
99
93
|
},
|
100
94
|
task: {
|
101
|
-
fileName:
|
95
|
+
fileName: hasJsModules ? 'Task.mjs' : 'taskworker.js'
|
102
96
|
},
|
103
97
|
vdom: {
|
104
|
-
fileName:
|
98
|
+
fileName: hasJsModules ? 'VDom.mjs' : 'vdomworker.js'
|
105
99
|
}
|
106
100
|
}
|
107
101
|
}
|
@@ -164,11 +158,11 @@ class Manager extends Base {
|
|
164
158
|
createWorker(opts) {
|
165
159
|
let me = this,
|
166
160
|
{fileName} = opts,
|
167
|
-
filePath = (opts.basePath ||
|
161
|
+
filePath = (opts.basePath || Neo.config.workerBasePath) + fileName,
|
168
162
|
name = `neomjs-${fileName.substring(0, fileName.indexOf('.')).toLowerCase()}-worker`,
|
169
163
|
isShared = me.sharedWorkersEnabled && NeoConfig.useSharedWorkers,
|
170
164
|
cls = isShared ? SharedWorker : Worker,
|
171
|
-
worker =
|
165
|
+
worker = hasJsModules
|
172
166
|
? new cls(filePath, {name, type: 'module'})
|
173
167
|
: new cls(filePath, {name});
|
174
168
|
|
@@ -295,7 +289,7 @@ class Manager extends Base {
|
|
295
289
|
*/
|
296
290
|
onWorkerError(e) {
|
297
291
|
// starting a worker from a JS module will show JS errors in a correct way
|
298
|
-
!
|
292
|
+
!hasJsModules && console.log('Worker Error:', e)
|
299
293
|
}
|
300
294
|
|
301
295
|
/**
|