Added support of Project Global Assets.
This commit is contained in:
+76
-1
@@ -9,6 +9,8 @@ import archiver from "archiver";
|
|||||||
import {buildWordPress} from "./platforms/wordpress/wordpress-adapter.js";
|
import {buildWordPress} from "./platforms/wordpress/wordpress-adapter.js";
|
||||||
import {buildHubspotEmail} from "./platforms/hubspot/hubspot-email-adapter.js";
|
import {buildHubspotEmail} from "./platforms/hubspot/hubspot-email-adapter.js";
|
||||||
import {buildHubspotPage} from "./platforms/hubspot/hubspot-page-adapter.js";
|
import {buildHubspotPage} from "./platforms/hubspot/hubspot-page-adapter.js";
|
||||||
|
import fs from "fs/promises";
|
||||||
|
import fetch from "node-fetch";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@@ -53,7 +55,7 @@ export async function getBlockData(jsonFileName = 'default', {projectPath} = {js
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getBlockConfigs(args = {modulesPath: '', dataFiles: []}) {
|
export function getBlockConfigs(args = {modulesPath: '', dataFiles: []}) {
|
||||||
return Object.assign(JSON.parse(JSON.stringify(config)), // The entire config object.
|
const updatedConfig = Object.assign(JSON.parse(JSON.stringify(config)), // The entire config object.
|
||||||
{
|
{
|
||||||
projectDir: args.modulesPath, dataFiles: args.dataFiles.map((name) => {
|
projectDir: args.modulesPath, dataFiles: args.dataFiles.map((name) => {
|
||||||
return {
|
return {
|
||||||
@@ -61,6 +63,14 @@ export function getBlockConfigs(args = {modulesPath: '', dataFiles: []}) {
|
|||||||
};
|
};
|
||||||
}), remToPx: config.has('remToPx') ? config.get('remToPx') : 16,
|
}), remToPx: config.has('remToPx') ? config.get('remToPx') : 16,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Avoid cache conflict on Global Project css/js files.
|
||||||
|
if (updatedConfig.project) {
|
||||||
|
updatedConfig.project.css = updatedConfig.project.css ? updatedConfig.project.css + '?cache=' + Date.now() : undefined;
|
||||||
|
updatedConfig.project.js = updatedConfig.project.js ? updatedConfig.project.js + '?cache=' + Date.now() : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBlockName(name = '') {
|
export function getBlockName(name = '') {
|
||||||
@@ -160,3 +170,68 @@ export async function buildExportFiles(blockName, platform) {
|
|||||||
await buildHubspotPage(blockName)
|
await buildHubspotPage(blockName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function removeCommentsFromCss(content) {
|
||||||
|
return content.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeCommentsFromJs(content) {
|
||||||
|
return content.replace(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function uploadFile(filePath, uploadUrl, validator) {
|
||||||
|
let body = await fs.readFile(filePath, {encoding: 'utf8'});
|
||||||
|
|
||||||
|
if (validator) {
|
||||||
|
body = validator(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(uploadUrl, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: body,
|
||||||
|
headers: {'Content-Type': 'application/javascript'}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.status !== 200;
|
||||||
|
} catch (err) {
|
||||||
|
const fileName = filePath.split('/').pop();
|
||||||
|
throw new Error(`Can't upload "${fileName}" file. Server permission error.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getImagesList(rootFolder, subFolder = '') {
|
||||||
|
const imagesPath = path.join(rootFolder, subFolder);
|
||||||
|
const images = await fs.readdir(imagesPath);
|
||||||
|
const imagesList = [];
|
||||||
|
|
||||||
|
for (const image of images) {
|
||||||
|
const stats = await fs.stat(path.join(imagesPath, image));
|
||||||
|
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
const subImages = await getImagesList(rootFolder, image);
|
||||||
|
imagesList.push(...subImages);
|
||||||
|
} else {
|
||||||
|
imagesList.push(path.join(subFolder, image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return imagesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function isFileEmpty(filePath, ignoreComments = false) {
|
||||||
|
const fileContent = await fs.readFile(filePath, 'utf8');
|
||||||
|
const lines = fileContent.split('\n');
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (ignoreComments && line.trim().startsWith('//')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.trim().length > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/swiper@8.4.5/swiper-bundle.min.css"/>
|
<link rel="stylesheet" href="https://unpkg.com/swiper@8.4.5/swiper-bundle.min.css"/>
|
||||||
|
{{#if config.project.css }} <link rel="stylesheet" href="{{ config.project.css }}">
|
||||||
|
{{/if}}
|
||||||
{{#if config.cssUrl }}
|
{{#if config.cssUrl }}
|
||||||
{{#each config.cssUrl }}
|
{{#each config.cssUrl }}
|
||||||
<link rel="stylesheet" href="{{ this }}">
|
<link rel="stylesheet" href="{{ this }}">
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
|
||||||
<script src="/scripts/dist/frame-index.min.js"></script>
|
<script src="/scripts/dist/frame-index.min.js"></script>
|
||||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||||
<script src="https://unpkg.com/swiper@8.4.5/swiper-bundle.min.js"></script>{{#if config.jsUrl }}
|
<script src="https://unpkg.com/swiper@8.4.5/swiper-bundle.min.js"></script>
|
||||||
|
{{#if config.project.js }}<script src="{{ config.project.js }}"></script>
|
||||||
|
{{/if}}
|
||||||
|
{{#if config.jsUrl }}
|
||||||
{{#each config.jsUrl }}<script src="{{ this }}"></script>
|
{{#each config.jsUrl }}<script src="{{ this }}"></script>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|||||||
+3
-3
@@ -7,9 +7,9 @@
|
|||||||
"url": "https://axe-web.com/"
|
"url": "https://axe-web.com/"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"info": "NODE_ENV=development BLOCK_NAME=comparison-table MODULE_PATH= node debug.js",
|
"info": "NODE_ENV=development BLOCK_NAME=content MODULE_PATH= node debug.js",
|
||||||
"dev": "NODE_ENV=development BLOCK_NAME=comparison-table MODULE_PATH= node server.js",
|
"dev": "NODE_ENV=development BLOCK_NAME=content MODULE_PATH= node server.js",
|
||||||
"build-platform": "NODE_ENV=development BLOCK_NAME=comparison-table MODULE_PATH= node ./build.js",
|
"build-platform": "NODE_ENV=development BLOCK_NAME=content MODULE_PATH= node ./build.js",
|
||||||
"dev-dev-tool": "NODE_ENV=development rollup --config rollup.config.js --watch",
|
"dev-dev-tool": "NODE_ENV=development rollup --config rollup.config.js --watch",
|
||||||
"build-dev-tool": "rollup --config rollup.config.js"
|
"build-dev-tool": "rollup --config rollup.config.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,7 +19,19 @@ import open from "open";
|
|||||||
import {sanitizeUrl} from "@braintree/sanitize-url";
|
import {sanitizeUrl} from "@braintree/sanitize-url";
|
||||||
import sanitizeHtml from 'sanitize-html';
|
import sanitizeHtml from 'sanitize-html';
|
||||||
import {escape} from "lodash-es";
|
import {escape} from "lodash-es";
|
||||||
import {getBlockData, getBlockConfigs, getConfigs, readJSONFile, zipProject} from "./helpers.js";
|
import {
|
||||||
|
getBlockConfigs,
|
||||||
|
getBlockData,
|
||||||
|
getBlockName,
|
||||||
|
getConfigs,
|
||||||
|
getImagesList,
|
||||||
|
isFileEmpty,
|
||||||
|
readJSONFile,
|
||||||
|
removeCommentsFromCss,
|
||||||
|
removeCommentsFromJs,
|
||||||
|
uploadFile,
|
||||||
|
zipProject
|
||||||
|
} from "./helpers.js";
|
||||||
import PluginError from 'plugin-error';
|
import PluginError from 'plugin-error';
|
||||||
import {Server} from "socket.io";
|
import {Server} from "socket.io";
|
||||||
import {createServer} from 'http';
|
import {createServer} from 'http';
|
||||||
@@ -93,7 +105,6 @@ app.get('/', (req, res) => {
|
|||||||
data.baseView = baseView;
|
data.baseView = baseView;
|
||||||
data.port = `/${baseViewUrl}`;
|
data.port = `/${baseViewUrl}`;
|
||||||
data.previewFrameUrl = `${previewFrameUrl}/${baseViewUrl}`;
|
data.previewFrameUrl = `${previewFrameUrl}/${baseViewUrl}`;
|
||||||
// data.previewFrameUrl = `/${baseViewUrl}`;
|
|
||||||
data.shareUrl = shareUrl;
|
data.shareUrl = shareUrl;
|
||||||
|
|
||||||
if (req.headers.referer) {
|
if (req.headers.referer) {
|
||||||
@@ -127,8 +138,24 @@ app.get('/view/:baseView', (req, res) => {
|
|||||||
|
|
||||||
app.get('/publish', async (req, res) => {
|
app.get('/publish', async (req, res) => {
|
||||||
const data = await readJSONFile(path.join(projectPath, `block.json`));
|
const data = await readJSONFile(path.join(projectPath, `block.json`));
|
||||||
|
|
||||||
|
data.static_files = {
|
||||||
|
css: getBlockName(data.name).name + '.min.css',
|
||||||
|
js: getBlockName(data.name).name + '.min.js',
|
||||||
|
images: await getImagesList(path.join(projectPath, 'src', 'images')),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await isFileEmpty(path.join(projectPath, `src/scripts`, data.static_files.js), true)) {
|
||||||
|
delete data.static_files.js;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.static_files.images.length) {
|
||||||
|
delete data.static_files.images;
|
||||||
|
}
|
||||||
|
|
||||||
let responseData = {
|
let responseData = {
|
||||||
uploadUrl: undefined
|
uploadBundleUrl: undefined,
|
||||||
|
staticFilesUrls: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -149,27 +176,53 @@ app.get('/publish', async (req, res) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseData.uploadUrl) {
|
// Start files uploading process.
|
||||||
await zipProject(path.join(projectPath, 'src'), path.join(projectPath, 'dist.zip'));
|
try {
|
||||||
const body = await fs.readFile(path.join(projectPath, 'dist.zip'));
|
if (responseData.uploadBundleUrl) {
|
||||||
const response = await fetch(`${responseData.uploadUrl}`, {
|
await zipProject(path.join(projectPath, 'src'), path.join(projectPath, 'dist.zip'));
|
||||||
method: 'PUT',
|
await uploadFile(path.join(projectPath, 'dist.zip'), responseData.uploadBundleUrl); // Bundle
|
||||||
body,
|
|
||||||
headers: {'Content-Type': 'application/zip'}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
res.json({success: false, message: "Can't upload the archive, permissions error."});
|
|
||||||
// TODO: Need to update the registry server.
|
|
||||||
await fs.unlink(path.join(projectPath, 'dist.zip'));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Upload CSS/JS/Images files only if the type of the unit is `foundation` or `component`.
|
||||||
|
if (responseData.staticFilesUrls.css) {
|
||||||
|
await uploadFile(
|
||||||
|
path.join(projectPath, 'src/styles', data.static_files.css),
|
||||||
|
responseData.staticFilesUrls.css.uploadUrl,
|
||||||
|
(data) => removeCommentsFromCss(data)); // CSS
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseData.staticFilesUrls.js) {
|
||||||
|
await uploadFile(
|
||||||
|
path.join(projectPath, 'src/scripts', data.static_files.js),
|
||||||
|
responseData.staticFilesUrls.js.uploadUrl,
|
||||||
|
(data) => removeCommentsFromJs(data)); // JS
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseData.staticFilesUrls.images) {
|
||||||
|
for (let i = 0; i < data.static_files.images.length; i++) {
|
||||||
|
await uploadFile(path.join(projectPath, 'src/images', data.static_files.images[i]),
|
||||||
|
responseData.staticFilesUrls.images[i].uploadUrl); // Images
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// TODO: Need to update the registry server.
|
||||||
|
await fs.unlink(path.join(projectPath, 'dist.zip')); // Remove local bundle
|
||||||
|
|
||||||
|
res.json({success: false, message: err.message});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await fs.unlink(path.join(projectPath, 'dist.zip')); // Remove local bundle
|
||||||
|
|
||||||
|
// TODO: Trigger build on the registry server only if the type of the unit is `foundation` or `component`.
|
||||||
|
try {
|
||||||
|
await triggerGlobalProjectFilesBuild(getBlockName(data.name).project);
|
||||||
|
} catch (err) {
|
||||||
|
res.json({success: false, message: 'Something wrong with Project Builder.'});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
res.json({success: true});
|
res.json({success: true});
|
||||||
|
|
||||||
await fs.unlink(path.join(projectPath, 'dist.zip'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/data', async (req, res) => {
|
app.get('/data', async (req, res) => {
|
||||||
@@ -177,7 +230,13 @@ app.get('/data', async (req, res) => {
|
|||||||
|
|
||||||
const dataFiles = prepareListOfDataFiles(await fs.readdir(path.join(projectPath, 'data')));
|
const dataFiles = prepareListOfDataFiles(await fs.readdir(path.join(projectPath, 'data')));
|
||||||
const data = await getBlockData(jsonDataFileName, {projectPath});
|
const data = await getBlockData(jsonDataFileName, {projectPath});
|
||||||
const designPreviewFiles = getListOfDesignPreviewFiles(jsonDataFileName, await fs.readdir(path.join(projectPath, 'design', 'preview')));
|
|
||||||
|
let designPreviewFiles = [];
|
||||||
|
try {
|
||||||
|
designPreviewFiles = getListOfDesignPreviewFiles(jsonDataFileName, await fs.readdir(path.join(projectPath, 'design', 'preview')));
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Preview Design doesn\'t exist');
|
||||||
|
}
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
dataOptions: dataFiles,
|
dataOptions: dataFiles,
|
||||||
@@ -439,3 +498,13 @@ async function getShareableUrl() {
|
|||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function triggerGlobalProjectFilesBuild(project) {
|
||||||
|
const response = await fetch(`${blocksRegistry}/project-files`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({project}),
|
||||||
|
headers: {'Content-Type': 'application/json'}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user