implements an easier pattern of pointing to files within config

This commit is contained in:
James
2020-09-19 19:31:04 -04:00
parent 20bf4680db
commit 939a2923d3
17 changed files with 248 additions and 87 deletions

View File

@@ -1,21 +1,23 @@
function stringify(obj) {
const path = require('path');
function stringify(obj, config) {
if (typeof obj === 'object') {
const result = [];
Object.keys(obj).forEach((key) => {
const val = stringify(obj[key]);
const val = stringify(obj[key], config);
if (val !== null) {
result.push(`"${key}": ${val}`);
}
});
return `{${result.join(',')}}`;
}
return `React.lazy(() => import('${obj}'))`;
return `React.lazy(() => import('${path.join(config.paths.configDir, obj)}'))`;
}
function recursivelyAddFieldComponents(fields) {
function recursivelyAddFieldComponents(fields, config) {
if (fields) {
return fields.reduce((allFields, field) => {
const subFields = recursivelyAddFieldComponents(field.fields);
const subFields = recursivelyAddFieldComponents(field.fields, config);
if (!field.name && field.fields) {
return {
@@ -55,7 +57,7 @@ function customComponents(config) {
const newComponents = { ...components };
newComponents[collection.slug] = {
fields: recursivelyAddFieldComponents(collection.fields),
fields: recursivelyAddFieldComponents(collection.fields, config),
...(collection.admin.components || {}),
};
@@ -66,7 +68,7 @@ function customComponents(config) {
const newComponents = { ...globals };
newComponents[global.slug] = {
fields: recursivelyAddFieldComponents(global.fields),
fields: recursivelyAddFieldComponents(global.fields, config),
...(global.admin.components || {}),
};
@@ -77,7 +79,7 @@ function customComponents(config) {
...(allCollectionComponents || {}),
...(allGlobalComponents || {}),
...(config.admin.components || {}),
}).replace(/\\/g, '\\\\');
}, config).replace(/\\/g, '\\\\');
return {
code: `

View File

@@ -9,3 +9,147 @@
}
}
}
/**
* atom-dark theme for `prism.js`
* Based on Atom's `atom-dark` theme: https://github.com/atom/atom-dark-syntax
* @author Joe Gibson (@gibsjose)
*/
code[class*="language-"],
pre[class*="language-"] {
color: #c5c8c6;
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: Inconsolata, Monaco, Consolas, 'Courier New', Courier, monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #1d1f21;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #7C7C7C;
}
.token.punctuation {
color: #c5c8c6;
}
.namespace {
opacity: .7;
}
.token.property,
.token.keyword,
.token.tag {
color: #96CBFE;
}
.token.class-name {
color: #FFFFB6;
text-decoration: underline;
}
.token.boolean,
.token.constant {
color: #99CC99;
}
.token.symbol,
.token.deleted {
color: #f92672;
}
.token.number {
color: #FF73FD;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #A8FF60;
}
.token.variable {
color: #C6C5FE;
}
.token.operator {
color: #EDEDED;
}
.token.entity {
color: #FFFFB6;
cursor: help;
}
.token.url {
color: #96CBFE;
}
.language-css .token.string,
.style .token.string {
color: #87C38A;
}
.token.atrule,
.token.attr-value {
color: #F9EE98;
}
.token.function {
color: #DAD085;
}
.token.regex {
color: #E9C062;
}
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}

View File

@@ -124,7 +124,6 @@ const propTypes = {
collection: PropTypes.shape({
slug: PropTypes.string,
upload: PropTypes.shape({
staticDir: PropTypes.string,
adminThumbnail: PropTypes.string,
}),
}).isRequired,

View File

@@ -1,4 +1,5 @@
const mkdirp = require('mkdirp');
const path = require('path');
const executeAccess = require('../../auth/executeAccess');
@@ -9,7 +10,7 @@ const getImageSize = require('../../uploads/getImageSize');
const imageMIMETypes = require('../../uploads/imageMIMETypes');
async function create(args) {
const { performFieldOperations } = this;
const { performFieldOperations, config } = this;
const {
collection: {
@@ -102,19 +103,21 @@ async function create(args) {
throw new MissingFile();
}
mkdirp.sync(staticDir);
const staticPath = path.join(config.paths.configDir, staticDir);
const fsSafeName = await getSafeFilename(staticDir, file.name);
mkdirp.sync(staticPath);
await file.mv(`${staticDir}/${fsSafeName}`);
const fsSafeName = await getSafeFilename(staticPath, file.name);
await file.mv(`${staticPath}/${fsSafeName}`);
if (imageMIMETypes.indexOf(file.mimetype) > -1) {
const dimensions = await getImageSize(`${staticDir}/${fsSafeName}`);
const dimensions = await getImageSize(`${staticPath}/${fsSafeName}`);
fileData.width = dimensions.width;
fileData.height = dimensions.height;
if (Array.isArray(imageSizes) && file.mimetype !== 'image/svg+xml') {
fileData.sizes = await resizeAndSave(collectionConfig, fsSafeName, fileData.mimeType);
fileData.sizes = await resizeAndSave(staticPath, collectionConfig, fsSafeName, fileData.mimeType);
}
}

View File

@@ -1,4 +1,6 @@
const fs = require('fs');
const path = require('path');
const { NotFound, Forbidden, ErrorDeletingFile } = require('../../errors');
const executeAccess = require('../../auth/executeAccess');
@@ -62,7 +64,9 @@ async function deleteQuery(args) {
if (collectionConfig.upload) {
const { staticDir } = collectionConfig.upload;
fs.unlink(`${staticDir}/${resultToDelete.filename}`, (err) => {
const staticPath = path.resolve(this.config.paths.configDir, staticDir);
fs.unlink(`${staticPath}/${resultToDelete.filename}`, (err) => {
if (err) {
throw new ErrorDeletingFile();
}
@@ -70,7 +74,7 @@ async function deleteQuery(args) {
if (resultToDelete.sizes) {
Object.values(resultToDelete.sizes).forEach((size) => {
fs.unlink(`${staticDir}/${size.filename}`, (err) => {
fs.unlink(`${staticPath}/${size.filename}`, (err) => {
if (err) {
throw new ErrorDeletingFile();
}

View File

@@ -1,5 +1,7 @@
const httpStatus = require('http-status');
const deepmerge = require('deepmerge');
const path = require('path');
const overwriteMerge = require('../../utilities/overwriteMerge');
const executeAccess = require('../../auth/executeAccess');
const { NotFound, Forbidden, APIError } = require('../../errors');
@@ -147,24 +149,26 @@ async function update(args) {
const { staticDir, imageSizes } = collectionConfig.upload;
const staticPath = path.resolve(this.config.paths.configDir, staticDir);
const file = (req.files && req.files.file) ? req.files.file : req.fileData;
if (file) {
const fsSafeName = await getSafeFilename(staticDir, file.name);
const fsSafeName = await getSafeFilename(staticPath, file.name);
await file.mv(`${staticDir}/${fsSafeName}`);
await file.mv(`${staticPath}/${fsSafeName}`);
fileData.filename = fsSafeName;
fileData.filesize = file.size;
fileData.mimeType = file.mimetype;
if (imageMIMETypes.indexOf(file.mimetype) > -1) {
const dimensions = await getImageSize(`${staticDir}/${fsSafeName}`);
const dimensions = await getImageSize(`${staticPath}/${fsSafeName}`);
fileData.width = dimensions.width;
fileData.height = dimensions.height;
if (Array.isArray(imageSizes) && file.mimetype !== 'image/svg+xml') {
fileData.sizes = await resizeAndSave(collectionConfig, fsSafeName, fileData.mimeType);
fileData.sizes = await resizeAndSave(staticPath, collectionConfig, fsSafeName, fileData.mimeType);
}
}

View File

@@ -1,5 +1,6 @@
const express = require('express');
const passport = require('passport');
const path = require('path');
const getExecuteStaticAccess = require('../auth/getExecuteStaticAccess');
const authenticate = require('./middleware/authenticate');
@@ -14,7 +15,10 @@ function initStatic() {
router.use(authenticate(this.config));
router.use(getExecuteStaticAccess(collection));
router.use(express.static(config.upload.staticDir));
const staticPath = path.resolve(this.config.paths.configDir, config.upload.staticDir);
router.use(express.static(staticPath));
this.express.use(`${config.upload.staticURL}`, router);
}

View File

@@ -19,11 +19,11 @@ const incrementName = (name) => {
return `${incrementedName}.${extension}`;
};
async function getSafeFileName(staticDir, desiredFilename) {
async function getSafeFileName(staticPath, desiredFilename) {
let modifiedFilename = desiredFilename;
// eslint-disable-next-line no-await-in-loop
while (await fileExists(`${staticDir}/${modifiedFilename}`)) {
while (await fileExists(`${staticPath}/${modifiedFilename}`)) {
modifiedFilename = incrementName(modifiedFilename);
}
return modifiedFilename;

View File

@@ -16,7 +16,7 @@ function getOutputImage(sourceImage, size) {
};
}
module.exports = async function resizeAndSave(config, savedFilename, mimeType) {
module.exports = async function resizeAndSave(staticPath, config, savedFilename, mimeType) {
/**
* Resize images according to image desired width and height and return sizes
* @param config Object
@@ -25,53 +25,48 @@ module.exports = async function resizeAndSave(config, savedFilename, mimeType) {
* @returns String[]
*/
const { imageSizes, staticDir } = config.upload;
const { imageSizes } = config.upload;
const sourceImage = `${staticDir}/${savedFilename}`;
let sizes;
try {
const dimensions = await getImageSize(sourceImage);
sizes = imageSizes
.filter(desiredSize => desiredSize.width < dimensions.width)
.map(async (desiredSize) => {
const outputImage = getOutputImage(savedFilename, desiredSize);
const imageNameWithDimensions = `${outputImage.name}-${outputImage.width}x${outputImage.height}.${outputImage.extension}`;
const imagePath = `${staticDir}/${imageNameWithDimensions}`;
const fileAlreadyExists = await fileExists(imagePath);
const sourceImage = `${staticPath}/${savedFilename}`;
if (fileAlreadyExists) {
fs.unlinkSync(imagePath);
}
const dimensions = await getImageSize(sourceImage);
const output = await sharp(sourceImage)
.resize(desiredSize.width, desiredSize.height, {
position: desiredSize.crop || 'centre',
})
.toFile(imagePath);
const sizes = imageSizes
.filter((desiredSize) => desiredSize.width < dimensions.width)
.map(async (desiredSize) => {
const outputImage = getOutputImage(savedFilename, desiredSize);
const imageNameWithDimensions = `${outputImage.name}-${outputImage.width}x${outputImage.height}.${outputImage.extension}`;
const imagePath = `${staticPath}/${imageNameWithDimensions}`;
const fileAlreadyExists = await fileExists(imagePath);
return {
...desiredSize,
filename: imageNameWithDimensions,
filesize: output.size,
mimeType,
};
});
if (fileAlreadyExists) {
fs.unlinkSync(imagePath);
}
const savedSizes = await Promise.all(sizes);
const output = await sharp(sourceImage)
.resize(desiredSize.width, desiredSize.height, {
position: desiredSize.crop || 'centre',
})
.toFile(imagePath);
return savedSizes.reduce((results, size) => {
return {
...results,
[size.name]: {
width: size.width,
height: size.height,
filename: size.filename,
mimeType: size.mimeType,
filesize: size.filesize,
},
...desiredSize,
filename: imageNameWithDimensions,
filesize: output.size,
mimeType,
};
}, {});
} catch (e) {
throw e;
}
});
const savedSizes = await Promise.all(sizes);
return savedSizes.reduce((results, size) => ({
...results,
[size.name]: {
width: size.width,
height: size.height,
filename: size.filename,
mimeType: size.mimeType,
filesize: size.filesize,
},
}), {});
};

View File

@@ -21,6 +21,7 @@ const getConfig = (options = {}) => {
mongoURL: options.mongoURL,
email: options.email,
paths: {
configDir: configPath.substring(0, configPath.lastIndexOf('/')),
...(publicConfig.paths || {}),
config: configPath,
},

View File

@@ -121,7 +121,9 @@ module.exports = (config) => {
},
plugins: [
new HtmlWebpackPlugin({
template: config.admin && config.admin.indexHTML ? config.admin.indexHTML : path.resolve(__dirname, '../client/index.html'),
template: config.admin && config.admin.indexHTML
? path.join(config.paths.configDir, config.admin.indexHTML)
: path.resolve(__dirname, '../client/index.html'),
filename: './index.html',
}),
new webpack.HotModuleReplacementPlugin(),
@@ -139,7 +141,7 @@ module.exports = (config) => {
}
if (config.paths.scss) {
webpackConfig.resolve.alias['payload-scss-overrides'] = config.paths.scss;
webpackConfig.resolve.alias['payload-scss-overrides'] = path.join(config.paths.configDir, config.paths.scss);
} else {
webpackConfig.resolve.alias['payload-scss-overrides'] = path.resolve(__dirname, '../client/scss/overrides.scss');
}

View File

@@ -110,7 +110,9 @@ module.exports = (config) => {
plugins: [
// new BundleAnalyzerPlugin(),
new HtmlWebpackPlugin({
template: config.admin && config.admin.indexHTML ? config.admin.indexHTML : path.resolve(__dirname, '../client/index.html'),
template: config.admin && config.admin.indexHTML
? path.join(config.paths.configDir, config.admin.indexHTML)
: path.resolve(__dirname, '../client/index.html'),
filename: './index.html',
minify: true,
}),
@@ -128,7 +130,7 @@ module.exports = (config) => {
}
if (config.paths.scss) {
webpackConfig.resolve.alias['payload-scss-overrides'] = config.paths.scss;
webpackConfig.resolve.alias['payload-scss-overrides'] = path.join(config.paths.configDir, config.paths.scss);
} else {
webpackConfig.resolve.alias['payload-scss-overrides'] = path.resolve(__dirname, '../client/scss/overrides.scss');
}