profitlich-template-toolkit 0.4.4 ā 0.5.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/package.json +14 -5
- package/scripts/copy-files.js +74 -0
- package/scripts/deploy.js +112 -0
- package/scss/forward.scss +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "profitlich-template-toolkit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Shared SCSS layout system, JS utilities and
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Shared SCSS layout system, JS utilities, components and build scripts for profitlich template repos",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./dev": "./dev/Dev.js",
|
|
@@ -14,15 +14,24 @@
|
|
|
14
14
|
"./utils/Vh100": "./utils/Vh100.js",
|
|
15
15
|
"./utils/BodyScrolled": "./utils/BodyScrolled.js",
|
|
16
16
|
"./components/menu-toggle/MenuToggle": "./components/menu-toggle/MenuToggle.js",
|
|
17
|
-
"./components/mux-player/MuxPlayer": "./components/mux-player/MuxPlayer.js"
|
|
17
|
+
"./components/mux-player/MuxPlayer": "./components/mux-player/MuxPlayer.js",
|
|
18
|
+
"./scripts/copy-files": "./scripts/copy-files.js",
|
|
19
|
+
"./scripts/deploy": "./scripts/deploy.js"
|
|
18
20
|
},
|
|
19
21
|
"files": [
|
|
20
22
|
"dev/",
|
|
21
23
|
"scss/",
|
|
22
24
|
"utils/",
|
|
23
|
-
"components/"
|
|
25
|
+
"components/",
|
|
26
|
+
"scripts/"
|
|
24
27
|
],
|
|
25
28
|
"dependencies": {
|
|
29
|
+
"basic-ftp": "^5.0.0",
|
|
30
|
+
"chokidar": "^4.0.0",
|
|
31
|
+
"cli-progress": "^3.12.0",
|
|
32
|
+
"dotenv": "^17.0.0",
|
|
33
|
+
"fs-extra": "^11.3.0",
|
|
34
|
+
"glob": "^11.0.0",
|
|
26
35
|
"lil-gui": "^0.21.0"
|
|
27
36
|
},
|
|
28
37
|
"peerDependencies": {
|
|
@@ -38,4 +47,4 @@
|
|
|
38
47
|
"url": "https://github.com/profitlich-ch/profitlich-template-toolkit"
|
|
39
48
|
},
|
|
40
49
|
"license": "MIT"
|
|
41
|
-
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import { glob } from 'glob';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import chokidar from 'chokidar';
|
|
5
|
+
|
|
6
|
+
async function runTask(task) {
|
|
7
|
+
const files = await glob(task.src, { nodir: true, dot: true });
|
|
8
|
+
if (files.length === 0) return;
|
|
9
|
+
|
|
10
|
+
for (const file of files) {
|
|
11
|
+
const relativePath = path.relative(task.base, file);
|
|
12
|
+
const destPath = path.join(task.dest, relativePath);
|
|
13
|
+
await fs.copy(file, destPath);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function copyAll(copyTasks) {
|
|
18
|
+
console.log('š Starting initial copy of all files...');
|
|
19
|
+
// empty folders to prevent orphaned files
|
|
20
|
+
for (const task of copyTasks) {
|
|
21
|
+
await fs.emptyDir(task.dest);
|
|
22
|
+
}
|
|
23
|
+
// run tasks parallely
|
|
24
|
+
await Promise.all(copyTasks.map(task => runTask(task)));
|
|
25
|
+
console.log('ā
Initial copy complete.');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function watchFiles(copyTasks, watchDir = 'src') {
|
|
29
|
+
console.log(`š Watching for file changes in ${watchDir}/`);
|
|
30
|
+
|
|
31
|
+
// set lock variable to prevent parallel copy tasks
|
|
32
|
+
let isCopying = false;
|
|
33
|
+
|
|
34
|
+
const watcher = chokidar.watch(watchDir, { ignored: /(^|[\/\\])\../, persistent: true });
|
|
35
|
+
|
|
36
|
+
watcher.on('all', async (event, filePath) => {
|
|
37
|
+
if (['add', 'change', 'unlink'].includes(event)) {
|
|
38
|
+
|
|
39
|
+
// only proceed if copy job is not running
|
|
40
|
+
if (isCopying) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log(`[${event}] ${filePath}. Re-copying all files...`);
|
|
45
|
+
|
|
46
|
+
// secure copy job with try...finally
|
|
47
|
+
try {
|
|
48
|
+
isCopying = true; // activate lock
|
|
49
|
+
await copyAll(copyTasks);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error("Error during copy:", err);
|
|
52
|
+
} finally {
|
|
53
|
+
isCopying = false; // deactivate lock, allow new copy job
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Run the copy-files script.
|
|
61
|
+
* @param {Array} copyTasks - array of { name, src, dest, base } objects
|
|
62
|
+
* @param {object} [options] - optional settings
|
|
63
|
+
* @param {string} [options.watchDir] - directory to watch (default: 'src')
|
|
64
|
+
*/
|
|
65
|
+
export function run(copyTasks, options = {}) {
|
|
66
|
+
const command = process.argv[2];
|
|
67
|
+
const watchDir = options.watchDir || 'src';
|
|
68
|
+
|
|
69
|
+
if (command === 'dev') {
|
|
70
|
+
copyAll(copyTasks).then(() => watchFiles(copyTasks, watchDir));
|
|
71
|
+
} else if (command === 'build') {
|
|
72
|
+
copyAll(copyTasks);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import ftp from 'basic-ftp';
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import readline from 'readline';
|
|
6
|
+
import cliProgress from 'cli-progress';
|
|
7
|
+
|
|
8
|
+
// Helper for making sure the upload progress bars go to 100%
|
|
9
|
+
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
10
|
+
|
|
11
|
+
export async function runDeploy(mode, uploadTasks) {
|
|
12
|
+
const client = new ftp.Client();
|
|
13
|
+
client.ftp.verbose = false;
|
|
14
|
+
let activeProgressBar = null;
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const modeUpper = mode.toUpperCase();
|
|
18
|
+
console.log(`š Starting deployment for: ${modeUpper}`);
|
|
19
|
+
|
|
20
|
+
await client.access({
|
|
21
|
+
host: process.env[`FTP_HOST_${modeUpper}`],
|
|
22
|
+
user: process.env[`FTP_USER_${modeUpper}`],
|
|
23
|
+
password: process.env[`FTP_PASSWORD_${modeUpper}`],
|
|
24
|
+
secure: true
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
for (const task of uploadTasks) {
|
|
28
|
+
console.log(`\nProcessing Task: ${task.name}`);
|
|
29
|
+
|
|
30
|
+
const files = await glob(task.localPattern, {
|
|
31
|
+
nodir: true,
|
|
32
|
+
dot: true,
|
|
33
|
+
ignore: task.ignore
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (files.length === 0) {
|
|
37
|
+
console.log('No files found for this task.');
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const newBar = new cliProgress.SingleBar({
|
|
42
|
+
format: ' Upload |{bar}| {percentage}% {value}/{total} files {duration_formatted}',
|
|
43
|
+
barCompleteChar: 'ā',
|
|
44
|
+
barIncompleteChar: 'ā',
|
|
45
|
+
hideCursor: true
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
activeProgressBar = newBar;
|
|
49
|
+
activeProgressBar.start(files.length, 0);
|
|
50
|
+
|
|
51
|
+
for (const file of files) {
|
|
52
|
+
const relativeFile = path.relative(task.localBase, file);
|
|
53
|
+
const remotePath = path.join(task.remoteDir, relativeFile).replace(/\\/g, '/');
|
|
54
|
+
|
|
55
|
+
await client.ensureDir(path.dirname(remotePath));
|
|
56
|
+
await client.uploadFrom(file, remotePath);
|
|
57
|
+
|
|
58
|
+
activeProgressBar.increment();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
activeProgressBar.stop();
|
|
62
|
+
activeProgressBar = null;
|
|
63
|
+
await delay(50);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log('\nā
Deployment completed successfully!');
|
|
67
|
+
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (activeProgressBar) {
|
|
70
|
+
activeProgressBar.stop();
|
|
71
|
+
}
|
|
72
|
+
console.error('Deployment failed:', err);
|
|
73
|
+
} finally {
|
|
74
|
+
client.close();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Run the deploy script.
|
|
80
|
+
* @param {Array} uploadTasks - array of { name, localPattern, localBase, remoteDir, ignore? }
|
|
81
|
+
*/
|
|
82
|
+
export function run(uploadTasks) {
|
|
83
|
+
const mode = process.argv[2];
|
|
84
|
+
if (!mode || (mode !== 'staging' && mode !== 'production')) {
|
|
85
|
+
console.error('Error: a mode needs to be given, either "staging" or "production"');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
dotenv.config();
|
|
90
|
+
|
|
91
|
+
// In production mode prompt for confirmation
|
|
92
|
+
if (mode === 'production') {
|
|
93
|
+
const rl = readline.createInterface({
|
|
94
|
+
input: process.stdin,
|
|
95
|
+
output: process.stdout
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
rl.question('š“ Do you really want to deploy to PRODUCTION? Type "yes" for confirmation: ', (answer) => {
|
|
99
|
+
rl.close();
|
|
100
|
+
if (answer.toLowerCase() === 'yes') {
|
|
101
|
+
console.log('Confirmed. Starting upload...');
|
|
102
|
+
runDeploy(mode, uploadTasks);
|
|
103
|
+
} else {
|
|
104
|
+
console.log('ā Deployment aborted.');
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
// In all other modes run deploy without prompt
|
|
109
|
+
} else {
|
|
110
|
+
runDeploy(mode, uploadTasks);
|
|
111
|
+
}
|
|
112
|
+
}
|
package/scss/forward.scss
CHANGED