Browse Source

Added support of Project Global Assets.

pull/9/head
Roman Axelrod 2 years ago
parent
commit
e2553358be
  1. 77
      helpers.js
  2. 2
      layouts/partials/head.hbs
  3. 5
      layouts/partials/scripts.hbs
  4. 6
      package.json
  5. 103
      server.js

77
helpers.js

@ -9,6 +9,8 @@ import archiver from "archiver";
import {buildWordPress} from "./platforms/wordpress/wordpress-adapter.js";
import {buildHubspotEmail} from "./platforms/hubspot/hubspot-email-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 __dirname = path.dirname(__filename);
@ -53,7 +55,7 @@ export async function getBlockData(jsonFileName = 'default', {projectPath} = {js
}
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) => {
return {
@ -61,6 +63,14 @@ export function getBlockConfigs(args = {modulesPath: '', dataFiles: []}) {
};
}), 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 = '') {
@ -160,3 +170,68 @@ export async function buildExportFiles(blockName, platform) {
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;
}

2
layouts/partials/head.hbs

@ -3,6 +3,8 @@
<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"/>
{{#if config.project.css }} <link rel="stylesheet" href="{{ config.project.css }}">
{{/if}}
{{#if config.cssUrl }}
{{#each config.cssUrl }}
<link rel="stylesheet" href="{{ this }}">

5
layouts/partials/scripts.hbs

@ -2,7 +2,10 @@
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.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://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}}
{{/if}}

6
package.json

@ -7,9 +7,9 @@
"url": "https://axe-web.com/"
},
"scripts": {
"info": "NODE_ENV=development BLOCK_NAME=comparison-table MODULE_PATH= node debug.js",
"dev": "NODE_ENV=development BLOCK_NAME=comparison-table MODULE_PATH= node server.js",
"build-platform": "NODE_ENV=development BLOCK_NAME=comparison-table MODULE_PATH= node ./build.js",
"info": "NODE_ENV=development BLOCK_NAME=content MODULE_PATH= node debug.js",
"dev": "NODE_ENV=development BLOCK_NAME=content MODULE_PATH= node server.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",
"build-dev-tool": "rollup --config rollup.config.js"
},

103
server.js

@ -19,7 +19,19 @@ import open from "open";
import {sanitizeUrl} from "@braintree/sanitize-url";
import sanitizeHtml from 'sanitize-html';
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 {Server} from "socket.io";
import {createServer} from 'http';
@ -93,7 +105,6 @@ app.get('/', (req, res) => {
data.baseView = baseView;
data.port = `/${baseViewUrl}`;
data.previewFrameUrl = `${previewFrameUrl}/${baseViewUrl}`;
// data.previewFrameUrl = `/${baseViewUrl}`;
data.shareUrl = shareUrl;
if (req.headers.referer) {
@ -127,8 +138,24 @@ app.get('/view/:baseView', (req, res) => {
app.get('/publish', async (req, res) => {
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 = {
uploadUrl: undefined
uploadBundleUrl: undefined,
staticFilesUrls: {}
};
try {
@ -149,27 +176,53 @@ app.get('/publish', async (req, res) => {
return;
}
if (responseData.uploadUrl) {
// Start files uploading process.
try {
if (responseData.uploadBundleUrl) {
await zipProject(path.join(projectPath, 'src'), path.join(projectPath, 'dist.zip'));
const body = await fs.readFile(path.join(projectPath, 'dist.zip'));
const response = await fetch(`${responseData.uploadUrl}`, {
method: 'PUT',
body,
headers: {'Content-Type': 'application/zip'}
});
await uploadFile(path.join(projectPath, 'dist.zip'), responseData.uploadBundleUrl); // Bundle
}
// 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 (response.status !== 200) {
res.json({success: false, message: "Can't upload the archive, permissions error."});
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'));
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
res.json({success: true});
// 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;
}
await fs.unlink(path.join(projectPath, 'dist.zip'));
res.json({success: true});
});
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 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({
dataOptions: dataFiles,
@ -439,3 +498,13 @@ async function getShareableUrl() {
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();
}

Loading…
Cancel
Save