core-maugli 1.2.41 → 1.2.43
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/netlify.toml +58 -0
- package/package.json +5 -3
- package/scripts/generate-netlify-config.js +164 -0
- package/scripts/update-all-blogs.js +23 -3
- package/src/config/maugli.config.ts +66 -0
package/netlify.toml
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Netlify configuration generated from maugli.config.ts
|
|
2
|
+
|
|
3
|
+
[build]
|
|
4
|
+
command = "npm run build"
|
|
5
|
+
publish = "dist"
|
|
6
|
+
|
|
7
|
+
[build.environment]
|
|
8
|
+
NODE_VERSION = "18"
|
|
9
|
+
NPM_FLAGS = "--legacy-peer-deps"
|
|
10
|
+
|
|
11
|
+
# Netlify plugins
|
|
12
|
+
[[plugins]]
|
|
13
|
+
package = "@netlify/plugin-lighthouse"
|
|
14
|
+
|
|
15
|
+
[[plugins]]
|
|
16
|
+
package = "netlify-plugin-submit-sitemap"
|
|
17
|
+
|
|
18
|
+
[[plugins]]
|
|
19
|
+
package = "netlify-plugin-checklinks"
|
|
20
|
+
|
|
21
|
+
[[plugins]]
|
|
22
|
+
package = "netlify-plugin-image-optim"
|
|
23
|
+
|
|
24
|
+
[[plugins]]
|
|
25
|
+
package = "netlify-plugin-minify-html"
|
|
26
|
+
|
|
27
|
+
[[plugins]]
|
|
28
|
+
package = "netlify-plugin-inline-critical-css"
|
|
29
|
+
|
|
30
|
+
[[plugins]]
|
|
31
|
+
package = "netlify-plugin-hashfiles"
|
|
32
|
+
|
|
33
|
+
# Redirects
|
|
34
|
+
[[redirects]]
|
|
35
|
+
from = "/blog/feed.xml"
|
|
36
|
+
to = "/rss.xml"
|
|
37
|
+
status = 301
|
|
38
|
+
|
|
39
|
+
# Headers
|
|
40
|
+
[[headers]]
|
|
41
|
+
for = "/*"
|
|
42
|
+
[headers.values]
|
|
43
|
+
"X-Frame-Options" = "DENY"
|
|
44
|
+
[headers.values]
|
|
45
|
+
"X-Content-Type-Options" = "nosniff"
|
|
46
|
+
[headers.values]
|
|
47
|
+
"Referrer-Policy" = "strict-origin-when-cross-origin"
|
|
48
|
+
|
|
49
|
+
[[headers]]
|
|
50
|
+
for = "/img/*"
|
|
51
|
+
[headers.values]
|
|
52
|
+
"Cache-Control" = "public, max-age=31536000, immutable"
|
|
53
|
+
|
|
54
|
+
[[headers]]
|
|
55
|
+
for = "/*.webp"
|
|
56
|
+
[headers.values]
|
|
57
|
+
"Cache-Control" = "public, max-age=31536000, immutable"
|
|
58
|
+
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "core-maugli",
|
|
3
3
|
"description": "Astro & Tailwind CSS blog theme for Maugli.",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "1.2.
|
|
5
|
+
"version": "1.2.43",
|
|
6
6
|
"license": "GPL-3.0-or-later OR Commercial",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"check-version": "node scripts/check-version.js",
|
|
40
40
|
"auto-update": "node scripts/auto-update.js",
|
|
41
41
|
"build:ci": "SKIP_VERSION_CHECK=true npm run build",
|
|
42
|
-
"
|
|
42
|
+
"generate-netlify": "node scripts/generate-netlify-config.js",
|
|
43
|
+
"postinstall": "node scripts/upgrade-config.js && node scripts/setup-user-images.js && node scripts/generate-netlify-config.js",
|
|
43
44
|
"generate-previews": "node scripts/generate-previews.js"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
@@ -85,7 +86,8 @@
|
|
|
85
86
|
"public/blackbox*.webp",
|
|
86
87
|
"scripts",
|
|
87
88
|
"bin",
|
|
88
|
-
".gitignore"
|
|
89
|
+
".gitignore",
|
|
90
|
+
"netlify.toml"
|
|
89
91
|
],
|
|
90
92
|
"bin": {
|
|
91
93
|
"core-maugli": "bin/index.js"
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate netlify.toml from maugli.config.ts
|
|
5
|
+
* This script creates a Netlify configuration file based on the Maugli configuration
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import ts from 'typescript';
|
|
12
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
|
|
17
|
+
async function loadTsModule(filePath) {
|
|
18
|
+
const code = await fs.promises.readFile(filePath, 'utf8');
|
|
19
|
+
const js = ts.transpileModule(code, {
|
|
20
|
+
compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2020 }
|
|
21
|
+
}).outputText;
|
|
22
|
+
const tmp = path.join(os.tmpdir(), `netlify-gen-${Date.now()}.mjs`);
|
|
23
|
+
await fs.promises.writeFile(tmp, js, 'utf8');
|
|
24
|
+
const mod = await import(pathToFileURL(tmp).href);
|
|
25
|
+
await fs.promises.unlink(tmp);
|
|
26
|
+
return mod;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function loadMaugliConfig() {
|
|
30
|
+
try {
|
|
31
|
+
// Try to load from user project first
|
|
32
|
+
const userConfigPath = path.join(process.cwd(), 'src/config/maugli.config.ts');
|
|
33
|
+
if (fs.existsSync(userConfigPath)) {
|
|
34
|
+
const mod = await loadTsModule(userConfigPath);
|
|
35
|
+
return mod.maugliConfig;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Fallback to default config
|
|
39
|
+
const defaultConfigPath = path.join(__dirname, '../src/config/maugli.config.ts');
|
|
40
|
+
const mod = await loadTsModule(defaultConfigPath);
|
|
41
|
+
return mod.maugliConfig;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.warn('Could not load maugli.config.ts:', error.message);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function generateNetlifyToml(config) {
|
|
49
|
+
const netlifyConfig = config.netlify || {};
|
|
50
|
+
|
|
51
|
+
let toml = `# Netlify configuration generated from maugli.config.ts\n\n`;
|
|
52
|
+
|
|
53
|
+
// Build settings
|
|
54
|
+
toml += `[build]\n`;
|
|
55
|
+
toml += ` command = "${netlifyConfig.buildCommand || 'npm run build'}"\n`;
|
|
56
|
+
toml += ` publish = "${netlifyConfig.publishDir || 'dist'}"\n\n`;
|
|
57
|
+
|
|
58
|
+
// Environment variables
|
|
59
|
+
if (netlifyConfig.environment) {
|
|
60
|
+
toml += `[build.environment]\n`;
|
|
61
|
+
|
|
62
|
+
// Add auto-update control
|
|
63
|
+
if (netlifyConfig.autoUpdate === false) {
|
|
64
|
+
toml += ` DISABLE_AUTO_UPDATE = "true"\n`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (const [key, value] of Object.entries(netlifyConfig.environment)) {
|
|
68
|
+
toml += ` ${key} = "${value}"\n`;
|
|
69
|
+
}
|
|
70
|
+
toml += `\n`;
|
|
71
|
+
} else if (netlifyConfig.autoUpdate === false) {
|
|
72
|
+
toml += `[build.environment]\n`;
|
|
73
|
+
toml += ` DISABLE_AUTO_UPDATE = "true"\n\n`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Plugins
|
|
77
|
+
if (netlifyConfig.plugins && netlifyConfig.plugins.length > 0) {
|
|
78
|
+
toml += `# Netlify plugins\n`;
|
|
79
|
+
netlifyConfig.plugins.forEach(plugin => {
|
|
80
|
+
toml += `[[plugins]]\n`;
|
|
81
|
+
toml += ` package = "${plugin}"\n\n`;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Redirects
|
|
86
|
+
if (netlifyConfig.redirects && netlifyConfig.redirects.length > 0) {
|
|
87
|
+
toml += `# Redirects\n`;
|
|
88
|
+
netlifyConfig.redirects.forEach(redirect => {
|
|
89
|
+
toml += `[[redirects]]\n`;
|
|
90
|
+
toml += ` from = "${redirect.from}"\n`;
|
|
91
|
+
toml += ` to = "${redirect.to}"\n`;
|
|
92
|
+
toml += ` status = ${redirect.status || 301}\n`;
|
|
93
|
+
if (redirect.force) {
|
|
94
|
+
toml += ` force = true\n`;
|
|
95
|
+
}
|
|
96
|
+
toml += `\n`;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Headers
|
|
101
|
+
if (netlifyConfig.headers && netlifyConfig.headers.length > 0) {
|
|
102
|
+
toml += `# Headers\n`;
|
|
103
|
+
netlifyConfig.headers.forEach(header => {
|
|
104
|
+
toml += `[[headers]]\n`;
|
|
105
|
+
toml += ` for = "${header.for}"\n`;
|
|
106
|
+
for (const [key, value] of Object.entries(header.values)) {
|
|
107
|
+
toml += ` [headers.values]\n`;
|
|
108
|
+
toml += ` "${key}" = "${value}"\n`;
|
|
109
|
+
}
|
|
110
|
+
toml += `\n`;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return toml;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function main() {
|
|
118
|
+
console.log('🔧 Generating netlify.toml from maugli.config.ts...');
|
|
119
|
+
|
|
120
|
+
const config = await loadMaugliConfig();
|
|
121
|
+
if (!config) {
|
|
122
|
+
console.warn('⚠️ Could not load maugli configuration, skipping netlify.toml generation');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const tomlContent = generateNetlifyToml(config);
|
|
127
|
+
const outputPath = path.join(process.cwd(), 'netlify.toml');
|
|
128
|
+
|
|
129
|
+
// Check if netlify.toml already exists
|
|
130
|
+
if (fs.existsSync(outputPath)) {
|
|
131
|
+
// Read existing content to check if it's auto-generated
|
|
132
|
+
const existingContent = fs.readFileSync(outputPath, 'utf8');
|
|
133
|
+
if (existingContent.includes('# Netlify configuration generated from maugli.config.ts')) {
|
|
134
|
+
console.log('🔄 Updating auto-generated netlify.toml...');
|
|
135
|
+
} else {
|
|
136
|
+
console.log('⚠️ Custom netlify.toml detected. Creating backup...');
|
|
137
|
+
fs.copyFileSync(outputPath, `${outputPath}.backup`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fs.writeFileSync(outputPath, tomlContent, 'utf8');
|
|
142
|
+
console.log('✅ netlify.toml generated successfully!');
|
|
143
|
+
|
|
144
|
+
if (config.netlify?.autoUpdate === false) {
|
|
145
|
+
console.log('🚫 Auto-update disabled in Netlify configuration');
|
|
146
|
+
} else {
|
|
147
|
+
console.log('🔄 Auto-update enabled for Netlify builds');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// List installed plugins
|
|
151
|
+
if (config.netlify?.plugins && config.netlify.plugins.length > 0) {
|
|
152
|
+
console.log('🔌 Netlify plugins configured:');
|
|
153
|
+
config.netlify.plugins.forEach(plugin => {
|
|
154
|
+
console.log(` • ${plugin}`);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console.log('📁 File location:', outputPath);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
main().catch(error => {
|
|
162
|
+
console.error('❌ Failed to generate netlify.toml:', error.message);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
});
|
|
@@ -14,7 +14,7 @@ import { execSync } from 'child_process';
|
|
|
14
14
|
import fs from 'fs';
|
|
15
15
|
import path from 'path';
|
|
16
16
|
|
|
17
|
-
const CURRENT_VERSION = '1.2.
|
|
17
|
+
const CURRENT_VERSION = '1.2.43';
|
|
18
18
|
|
|
19
19
|
// Правильные скрипты для package.json
|
|
20
20
|
const CORRECT_SCRIPTS = {
|
|
@@ -39,6 +39,7 @@ const CORRECT_SCRIPTS = {
|
|
|
39
39
|
"check-version": "node scripts/check-version.js",
|
|
40
40
|
"auto-update": "node scripts/auto-update.js",
|
|
41
41
|
"build:ci": "SKIP_VERSION_CHECK=true npm run build",
|
|
42
|
+
"generate-netlify": "node scripts/generate-netlify-config.js",
|
|
42
43
|
"postinstall": "node scripts/upgrade-config.js && node scripts/setup-user-images.js",
|
|
43
44
|
"generate-previews": "node scripts/generate-previews.js"
|
|
44
45
|
};
|
|
@@ -56,7 +57,9 @@ const REQUIRED_SCRIPTS = [
|
|
|
56
57
|
'scripts/update-with-backup.js',
|
|
57
58
|
'scripts/check-version.js',
|
|
58
59
|
'scripts/auto-update.js',
|
|
59
|
-
'.
|
|
60
|
+
'scripts/generate-netlify-config.js',
|
|
61
|
+
'.gitignore',
|
|
62
|
+
'netlify.toml'
|
|
60
63
|
];
|
|
61
64
|
|
|
62
65
|
function log(message, type = 'info') {
|
|
@@ -152,7 +155,23 @@ function updateBlogProject(projectPath) {
|
|
|
152
155
|
process.chdir(absolutePath);
|
|
153
156
|
execSync('npm update core-maugli', { stdio: 'pipe' });
|
|
154
157
|
|
|
155
|
-
// 8.
|
|
158
|
+
// 8. Генерируем netlify.toml
|
|
159
|
+
log('Generating netlify.toml configuration...', 'info');
|
|
160
|
+
const generateNetlifyScript = path.join(process.cwd(), 'scripts/generate-netlify-config.js');
|
|
161
|
+
if (fs.existsSync(generateNetlifyScript)) {
|
|
162
|
+
try {
|
|
163
|
+
const { execSync } = require('child_process');
|
|
164
|
+
execSync(`node "${generateNetlifyScript}"`, {
|
|
165
|
+
stdio: 'pipe',
|
|
166
|
+
cwd: absolutePath
|
|
167
|
+
});
|
|
168
|
+
log(' ✅ netlify.toml generated', 'success');
|
|
169
|
+
} catch (error) {
|
|
170
|
+
log(` ⚠️ netlify.toml generation failed: ${error.message}`, 'warn');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 9. Результат
|
|
156
175
|
log(`Project updated successfully!`, 'success');
|
|
157
176
|
log(` Version: ${oldVersion} → ${CURRENT_VERSION}`, 'info');
|
|
158
177
|
log(` Scripts updated: ${scriptsUpdated ? 'Yes' : 'No'}`, 'info');
|
|
@@ -192,6 +211,7 @@ function main() {
|
|
|
192
211
|
log(' ✅ Correct core-maugli version', 'success');
|
|
193
212
|
log(' ✅ Up-to-date build scripts', 'success');
|
|
194
213
|
log(' ✅ Working image optimization', 'success');
|
|
214
|
+
log(' ✅ Auto-generated netlify.toml', 'success');
|
|
195
215
|
}
|
|
196
216
|
}
|
|
197
217
|
|
|
@@ -24,6 +24,24 @@ export interface MaugliConfig {
|
|
|
24
24
|
url?: string; // User's repository URL for Netlify deployment button
|
|
25
25
|
netlifyEnabled?: boolean; // Enable Netlify deployment button (default: true)
|
|
26
26
|
};
|
|
27
|
+
// Netlify deployment configuration
|
|
28
|
+
netlify?: {
|
|
29
|
+
autoUpdate?: boolean; // Enable auto-update on Netlify (default: true)
|
|
30
|
+
plugins?: string[]; // Netlify plugins to install
|
|
31
|
+
buildCommand?: string; // Custom build command for Netlify
|
|
32
|
+
publishDir?: string; // Publish directory (default: "dist")
|
|
33
|
+
environment?: Record<string, string>; // Environment variables for Netlify
|
|
34
|
+
redirects?: Array<{
|
|
35
|
+
from: string;
|
|
36
|
+
to: string;
|
|
37
|
+
status?: number;
|
|
38
|
+
force?: boolean;
|
|
39
|
+
}>; // Custom redirects
|
|
40
|
+
headers?: Array<{
|
|
41
|
+
for: string;
|
|
42
|
+
values: Record<string, string>;
|
|
43
|
+
}>; // Custom headers
|
|
44
|
+
};
|
|
27
45
|
// Brand and logo settings
|
|
28
46
|
brand: {
|
|
29
47
|
name: string; // Brand name
|
|
@@ -122,6 +140,54 @@ export const maugliConfig: MaugliConfig = {
|
|
|
122
140
|
url: 'https://github.com/dashapps/core-maugli-blog', // User's repository URL for Netlify deployment button
|
|
123
141
|
netlifyEnabled: true, // Enable Netlify deployment button (default: true)
|
|
124
142
|
},
|
|
143
|
+
// Netlify deployment configuration
|
|
144
|
+
netlify: {
|
|
145
|
+
autoUpdate: true, // Enable auto-update on Netlify (default: true)
|
|
146
|
+
plugins: [
|
|
147
|
+
'@netlify/plugin-lighthouse', // Lighthouse performance audits
|
|
148
|
+
'netlify-plugin-submit-sitemap', // Auto-submit sitemap to search engines
|
|
149
|
+
'netlify-plugin-checklinks', // Check for broken links
|
|
150
|
+
'netlify-plugin-image-optim', // Image optimization
|
|
151
|
+
'netlify-plugin-minify-html', // HTML minification
|
|
152
|
+
'netlify-plugin-inline-critical-css', // Inline critical CSS
|
|
153
|
+
'netlify-plugin-hashfiles' // Cache optimization with file hashing
|
|
154
|
+
], // Recommended Netlify plugins from UI
|
|
155
|
+
buildCommand: 'npm run build', // Default build command
|
|
156
|
+
publishDir: 'dist', // Astro output directory
|
|
157
|
+
environment: {
|
|
158
|
+
NODE_VERSION: '18',
|
|
159
|
+
NPM_FLAGS: '--legacy-peer-deps'
|
|
160
|
+
}, // Default environment variables
|
|
161
|
+
redirects: [
|
|
162
|
+
{
|
|
163
|
+
from: '/blog/feed.xml',
|
|
164
|
+
to: '/rss.xml',
|
|
165
|
+
status: 301
|
|
166
|
+
}
|
|
167
|
+
], // Common redirects
|
|
168
|
+
headers: [
|
|
169
|
+
{
|
|
170
|
+
for: '/*',
|
|
171
|
+
values: {
|
|
172
|
+
'X-Frame-Options': 'DENY',
|
|
173
|
+
'X-Content-Type-Options': 'nosniff',
|
|
174
|
+
'Referrer-Policy': 'strict-origin-when-cross-origin'
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
for: '/img/*',
|
|
179
|
+
values: {
|
|
180
|
+
'Cache-Control': 'public, max-age=31536000, immutable'
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
for: '/*.webp',
|
|
185
|
+
values: {
|
|
186
|
+
'Cache-Control': 'public, max-age=31536000, immutable'
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
] // Security and performance headers
|
|
190
|
+
},
|
|
125
191
|
enableThemeSwitcher: true, // Enable theme switcher (true by default)
|
|
126
192
|
defaultTheme: 'dark', // Default theme (dark by default)
|
|
127
193
|
seo: {
|