progress to buildConfig, splitting out type organization
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
const config = require('./src/babel.config');
|
const config = require('./src/babel.config');
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = (api) => config(api);
|
||||||
|
|||||||
1
config.d.ts
vendored
Normal file
1
config.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './dist/config';
|
||||||
@@ -9,12 +9,4 @@ module.exports = {
|
|||||||
'dist',
|
'dist',
|
||||||
],
|
],
|
||||||
testTimeout: 15000,
|
testTimeout: 15000,
|
||||||
moduleNameMapper: {
|
|
||||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/tests/mocks/fileMock.js',
|
|
||||||
'\\.(css|scss)$': '<rootDir>/tests/mocks/emptyModule.js',
|
|
||||||
},
|
|
||||||
transform: {
|
|
||||||
'\\.(css|less|scss)$': './tests/stub-transformer.js',
|
|
||||||
'\\.(js|jsx|ts|tsx)$': 'babel-jest',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import unsanitizedConfig from 'payload/unsanitizedConfig';
|
import unsanitizedConfig from 'payload/unsanitizedConfig';
|
||||||
import sanitizeConfig from '../../../../utilities/sanitizeConfig';
|
import sanitizeConfig from '../../../../config/sanitize';
|
||||||
import Context from './context';
|
import Context from './context';
|
||||||
|
|
||||||
const sanitizedConfig = sanitizeConfig(unsanitizedConfig);
|
const sanitizedConfig = sanitizeConfig(unsanitizedConfig);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { MongoClient } from 'mongodb';
|
import { MongoClient } from 'mongodb';
|
||||||
import getConfig from '../utilities/getConfig';
|
import getConfig from '../config/load';
|
||||||
import { email, password, mongo } from '../../tests/api/credentials';
|
import { email, password, mongo } from '../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = (api) => {
|
||||||
|
const config = {
|
||||||
presets: [
|
presets: [
|
||||||
'@babel/typescript',
|
'@babel/typescript',
|
||||||
[
|
[
|
||||||
@@ -17,11 +18,17 @@ module.exports = {
|
|||||||
require.resolve('@babel/plugin-transform-runtime'),
|
require.resolve('@babel/plugin-transform-runtime'),
|
||||||
require.resolve('@babel/plugin-proposal-class-properties'),
|
require.resolve('@babel/plugin-proposal-class-properties'),
|
||||||
require.resolve('@babel/plugin-proposal-optional-chaining'),
|
require.resolve('@babel/plugin-proposal-optional-chaining'),
|
||||||
[
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (api.env('test')) {
|
||||||
|
config.plugins.push([
|
||||||
'babel-plugin-ignore-html-and-css-imports',
|
'babel-plugin-ignore-html-and-css-imports',
|
||||||
{
|
{
|
||||||
removeExtensions: ['.svg', '.css', '.scss', '.png', '.jpg'],
|
removeExtensions: ['.svg', '.css', '.scss', '.png', '.jpg'],
|
||||||
},
|
},
|
||||||
],
|
]);
|
||||||
],
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const getWebpackProdConfig = require('../webpack/getWebpackProdConfig');
|
const getWebpackProdConfig = require('../webpack/getWebpackProdConfig');
|
||||||
const findConfig = require('../utilities/findConfig');
|
const findConfig = require('../config/find');
|
||||||
const getConfig = require('../utilities/getConfig');
|
const getConfig = require('../config/load');
|
||||||
const sanitizeConfig = require('../utilities/sanitizeConfig');
|
const sanitizeConfig = require('../config/sanitize');
|
||||||
|
|
||||||
const configPath = findConfig();
|
const configPath = findConfig();
|
||||||
|
|
||||||
|
|||||||
10
src/collections/config/build.ts
Normal file
10
src/collections/config/build.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Collection } from './types';
|
||||||
|
import sanitize from './sanitize';
|
||||||
|
|
||||||
|
const buildCollection = (collection: Collection) => {
|
||||||
|
const sanitized = sanitize(collection);
|
||||||
|
|
||||||
|
return sanitized;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = buildCollection;
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import merge from 'deepmerge';
|
import merge from 'deepmerge';
|
||||||
import sanitizeFields from '../fields/sanitize';
|
import sanitizeFields from '../../fields/config/sanitize';
|
||||||
import toKebabCase from '../utilities/toKebabCase';
|
import toKebabCase from '../../utilities/toKebabCase';
|
||||||
import baseAuthFields from '../fields/baseFields/baseFields';
|
import baseAuthFields from '../../fields/baseFields/baseFields';
|
||||||
import baseAPIKeyFields from '../fields/baseFields/baseAPIKeyFields';
|
import baseAPIKeyFields from '../../fields/baseFields/baseAPIKeyFields';
|
||||||
import baseVerificationFields from '../fields/baseFields/baseVerificationFields';
|
import baseVerificationFields from '../../fields/baseFields/baseVerificationFields';
|
||||||
import baseAccountLockFields from '../fields/baseFields/baseAccountLockFields';
|
import baseAccountLockFields from '../../fields/baseFields/baseAccountLockFields';
|
||||||
import baseUploadFields from '../fields/baseFields/baseUploadFields';
|
import baseUploadFields from '../../fields/baseFields/baseUploadFields';
|
||||||
import baseImageUploadFields from '../fields/baseFields/baseImageUploadFields';
|
import baseImageUploadFields from '../../fields/baseFields/baseImageUploadFields';
|
||||||
import formatLabels from '../utilities/formatLabels';
|
import formatLabels from '../../utilities/formatLabels';
|
||||||
|
|
||||||
const mergeBaseFields = (fields, baseFields) => {
|
const mergeBaseFields = (fields, baseFields) => {
|
||||||
const mergedFields = [];
|
const mergedFields = [];
|
||||||
47
src/collections/config/types.ts
Normal file
47
src/collections/config/types.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
export type Collection = {
|
||||||
|
slug: string;
|
||||||
|
labels?: {
|
||||||
|
singular: string;
|
||||||
|
plural: string;
|
||||||
|
};
|
||||||
|
admin?: {
|
||||||
|
useAsTitle?: string;
|
||||||
|
defaultColumns?: string[];
|
||||||
|
components?: any;
|
||||||
|
};
|
||||||
|
hooks?: {
|
||||||
|
beforeOperation?: Hook[];
|
||||||
|
beforeValidate?: Hook[];
|
||||||
|
beforeChange?: Hook[];
|
||||||
|
afterChange?: Hook[];
|
||||||
|
beforeRead?: Hook[];
|
||||||
|
afterRead?: Hook[];
|
||||||
|
beforeDelete?: Hook[];
|
||||||
|
afterDelete?: Hook[];
|
||||||
|
};
|
||||||
|
access?: {
|
||||||
|
create?: Access;
|
||||||
|
read?: Access;
|
||||||
|
update?: Access;
|
||||||
|
delete?: Access;
|
||||||
|
admin?: Access;
|
||||||
|
};
|
||||||
|
auth?: {
|
||||||
|
tokenExpiration?: number;
|
||||||
|
verify?:
|
||||||
|
| boolean
|
||||||
|
| { generateEmailHTML: string; generateEmailSubject: string };
|
||||||
|
maxLoginAttempts?: number;
|
||||||
|
lockTime?: number;
|
||||||
|
useAPIKey?: boolean;
|
||||||
|
cookies?:
|
||||||
|
| {
|
||||||
|
secure?: boolean;
|
||||||
|
sameSite?: string;
|
||||||
|
domain?: string | undefined;
|
||||||
|
}
|
||||||
|
| boolean;
|
||||||
|
};
|
||||||
|
fields: Field[];
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
* @jest-environment node
|
* @jest-environment node
|
||||||
*/
|
*/
|
||||||
import { request, GraphQLClient } from 'graphql-request';
|
import { request, GraphQLClient } from 'graphql-request';
|
||||||
import getConfig from '../../../utilities/getConfig';
|
import getConfig from '../../../config/load';
|
||||||
import { email, password } from '../../../../tests/api/credentials';
|
import { email, password } from '../../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import getConfig from '../../utilities/getConfig';
|
import getConfig from '../../config/load';
|
||||||
import { email, password } from '../../../tests/api/credentials';
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import getConfig from '../../utilities/getConfig';
|
import getConfig from '../../config/load';
|
||||||
import { email, password } from '../../../tests/api/credentials';
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import getConfig from '../../utilities/getConfig';
|
import getConfig from '../../config/load';
|
||||||
import { email, password } from '../../../tests/api/credentials';
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
import getConfig from '../../utilities/getConfig';
|
import getConfig from '../../config/load';
|
||||||
import fileExists from '../../../tests/api/utils/fileExists';
|
import fileExists from '../../../tests/api/utils/fileExists';
|
||||||
import { email, password } from '../../../tests/api/credentials';
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
|
|||||||
12
src/config/build.ts
Normal file
12
src/config/build.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { PayloadConfig } from '../types';
|
||||||
|
import sanitize from './sanitize';
|
||||||
|
import validate from './validate';
|
||||||
|
|
||||||
|
const buildConfig = (config: PayloadConfig) => {
|
||||||
|
const validated = validate(config);
|
||||||
|
const sanitized = sanitize(validated);
|
||||||
|
|
||||||
|
return sanitized;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = buildConfig;
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
/* eslint-disable import/no-dynamic-require */
|
/* eslint-disable import/no-dynamic-require */
|
||||||
/* eslint-disable global-require */
|
/* eslint-disable global-require */
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import findConfig from './findConfig';
|
import { Config } from './types';
|
||||||
|
import findConfig from './find';
|
||||||
|
|
||||||
const configPath = findConfig();
|
const configPath = findConfig();
|
||||||
const getConfig = () => {
|
const getConfig = (): Config => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const publicConfig = require(configPath);
|
const publicConfig = require(configPath);
|
||||||
return {
|
return {
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
import { PayloadConfig } from '../types';
|
import { Config } from './types';
|
||||||
import defaultUser from '../auth/default';
|
import defaultUser from '../auth/default';
|
||||||
import sanitizeCollection from '../collections/sanitize';
|
import sanitizeCollection from '../collections/config/sanitize';
|
||||||
import { InvalidConfiguration } from '../errors';
|
import { InvalidConfiguration } from '../errors';
|
||||||
import sanitizeGlobals from '../globals/sanitize';
|
import sanitizeGlobals from '../globals/config/sanitize';
|
||||||
import validateSchema from '../schema/validateSchema';
|
import checkDuplicateCollections from '../utilities/checkDuplicateCollections';
|
||||||
import checkDuplicateCollections from './checkDuplicateCollections';
|
|
||||||
|
|
||||||
const sanitizeConfig = (config: PayloadConfig) => {
|
const sanitizeConfig = (config: Config): Config => {
|
||||||
const sanitizedConfig = validateSchema({ ...config });
|
const sanitizedConfig = { ...config };
|
||||||
|
|
||||||
// TODO: remove default values from sanitize in favor of assigning in the schema within validateSchema and use https://www.npmjs.com/package/ajv#coercing-data-types where needed
|
// TODO: remove default values from sanitize in favor of assigning in the schema within validateSchema and use https://www.npmjs.com/package/ajv#coercing-data-types where needed
|
||||||
if (sanitizedConfig.publicENV === undefined) sanitizedConfig.publicENV = {};
|
if (sanitizedConfig.publicENV === undefined) sanitizedConfig.publicENV = {};
|
||||||
107
src/config/types.ts
Normal file
107
src/config/types.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import { Express } from 'express';
|
||||||
|
import { CSSProperties } from 'react';
|
||||||
|
import { Transporter } from 'nodemailer';
|
||||||
|
import SMTPConnection from 'nodemailer/lib/smtp-connection';
|
||||||
|
import { Collection } from '../collections/config/types';
|
||||||
|
|
||||||
|
type MockEmailTransport = {
|
||||||
|
transport?: 'mock';
|
||||||
|
fromName?: string;
|
||||||
|
fromAddress?: string;
|
||||||
|
};
|
||||||
|
type ValidEmailTransport = {
|
||||||
|
transport: Transporter;
|
||||||
|
transportOptions?: SMTPConnection.Options;
|
||||||
|
fromName: string;
|
||||||
|
fromAddress: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EmailOptions = ValidEmailTransport | MockEmailTransport;
|
||||||
|
|
||||||
|
export type InitOptions = {
|
||||||
|
express?: Express;
|
||||||
|
mongoURL: string;
|
||||||
|
secret: string;
|
||||||
|
license?: string;
|
||||||
|
email?: EmailOptions;
|
||||||
|
local?: boolean; // I have no idea what this is
|
||||||
|
onInit?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SendEmailOptions = {
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
subject: string;
|
||||||
|
html: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MockEmailCredentials = {
|
||||||
|
user: string;
|
||||||
|
pass: string;
|
||||||
|
web: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Hook = (...args: any[]) => any | void;
|
||||||
|
export type Access = (args?: any) => boolean;
|
||||||
|
|
||||||
|
export type Config = {
|
||||||
|
admin?: {
|
||||||
|
user?: string
|
||||||
|
meta?: {
|
||||||
|
titleSuffix?: string
|
||||||
|
ogImage?: string
|
||||||
|
favicon?: string
|
||||||
|
}
|
||||||
|
disable?: boolean
|
||||||
|
};
|
||||||
|
collections?: Collection[];
|
||||||
|
globals?: Global[];
|
||||||
|
serverURL?: string;
|
||||||
|
cookiePrefix?: string;
|
||||||
|
csrf?: string[];
|
||||||
|
cors?: string[];
|
||||||
|
publicENV: { [key: string]: string };
|
||||||
|
routes?: {
|
||||||
|
api?: string;
|
||||||
|
admin?: string;
|
||||||
|
graphQL?: string;
|
||||||
|
graphQLPlayground?: string;
|
||||||
|
};
|
||||||
|
email?: EmailOptions;
|
||||||
|
local?: boolean;
|
||||||
|
defaultDepth?: number;
|
||||||
|
maxDepth?: number;
|
||||||
|
rateLimit?: {
|
||||||
|
window?: number;
|
||||||
|
max?: number;
|
||||||
|
trustProxy?: boolean;
|
||||||
|
skip?: (req: Request) => boolean; // TODO: Type join Request w/ PayloadRequest
|
||||||
|
};
|
||||||
|
upload?: {
|
||||||
|
limits?: {
|
||||||
|
fileSize?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
localization?: {
|
||||||
|
locales: string[];
|
||||||
|
};
|
||||||
|
defaultLocale?: string;
|
||||||
|
fallback?: boolean;
|
||||||
|
graphQL?: {
|
||||||
|
mutations?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
},
|
||||||
|
queries?: {
|
||||||
|
[key: string]: unknown
|
||||||
|
},
|
||||||
|
maxComplexity?: number;
|
||||||
|
disablePlaygroundInProduction?: boolean;
|
||||||
|
};
|
||||||
|
components: { [key: string]: JSX.Element | (() => JSX.Element) };
|
||||||
|
paths?: { [key: string]: string };
|
||||||
|
hooks?: {
|
||||||
|
afterError?: () => void;
|
||||||
|
};
|
||||||
|
webpack?: (config: any) => any;
|
||||||
|
serverModules?: string[];
|
||||||
|
};
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import Ajv from 'ajv';
|
import Ajv from 'ajv';
|
||||||
import * as payloadSchema from './payload.schema.json';
|
import * as configSchema from './schema.json';
|
||||||
import * as collectionSchema from './collection.schema.json';
|
import * as collectionSchema from '../collections/config/schema.json';
|
||||||
|
|
||||||
import InvalidSchema from '../errors/InvalidSchema';
|
import InvalidSchema from '../errors/InvalidSchema';
|
||||||
import { PayloadConfig } from '../types';
|
import { PayloadConfig } from './types';
|
||||||
|
|
||||||
const validateSchema = (config: PayloadConfig) => {
|
const validateSchema = (config: PayloadConfig): PayloadConfig => {
|
||||||
const ajv = new Ajv({ useDefaults: true });
|
const ajv = new Ajv({ useDefaults: true });
|
||||||
const validate = ajv.addSchema(collectionSchema, '/collection.schema.json')
|
const validate = ajv.addSchema(collectionSchema, '../collections/config/schema.json').compile(configSchema);
|
||||||
.compile(payloadSchema);
|
|
||||||
const valid = validate(config);
|
const valid = validate(config);
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new InvalidSchema(`Invalid payload config provided. Found ${validate.errors.length} errors`, validate.errors);
|
throw new InvalidSchema(`Invalid payload config provided. Found ${validate.errors.length} errors`, validate.errors);
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
const babelConfig = require('./babel.config');
|
const babelConfig = require('./babel.config')({
|
||||||
|
env: () => false,
|
||||||
|
});
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'test') {
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
// eslint-disable-next-line global-require
|
// eslint-disable-next-line global-require
|
||||||
require('@babel/register')({
|
require('@babel/register')({
|
||||||
...babelConfig,
|
...babelConfig,
|
||||||
ignore: [
|
|
||||||
/node_modules[\\/](?!@payloadcms[\\/]payload[\\/]src[\\/]admin|@payloadcms[\\/]payload[\\/]components|@payloadcms[\\/]payload[\\/]hooks).*/,
|
|
||||||
],
|
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||||
plugins: [
|
plugins: [
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import nodemailer, { Transporter } from 'nodemailer';
|
import nodemailer, { Transporter } from 'nodemailer';
|
||||||
import { PayloadEmailOptions } from '../types';
|
import { EmailOptions } from '../config/types';
|
||||||
import { InvalidConfiguration } from '../errors';
|
import { InvalidConfiguration } from '../errors';
|
||||||
import mockHandler from './mockHandler';
|
import mockHandler from './mockHandler';
|
||||||
import Logger from '../utilities/logger';
|
import Logger from '../utilities/logger';
|
||||||
|
import { BuildEmailResult } from './types';
|
||||||
|
|
||||||
const logger = Logger();
|
const logger = Logger();
|
||||||
|
|
||||||
export default async function buildEmail(emailConfig: PayloadEmailOptions) {
|
export default async function buildEmail(emailConfig: EmailOptions): BuildEmailResult {
|
||||||
if (!emailConfig.transport || emailConfig.transport === 'mock') {
|
if (!emailConfig.transport || emailConfig.transport === 'mock') {
|
||||||
const mockAccount = await mockHandler(emailConfig);
|
const mockAccount = await mockHandler(emailConfig);
|
||||||
// Only log mock credentials if was explicitly set in config
|
// Only log mock credentials if was explicitly set in config
|
||||||
@@ -38,8 +40,8 @@ export default async function buildEmail(emailConfig: PayloadEmailOptions) {
|
|||||||
email.transport = transport;
|
email.transport = transport;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(
|
||||||
"There is an error with the email configuration you have provided.",
|
'There is an error with the email configuration you have provided.',
|
||||||
err
|
err,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
import { TestAccount, Transporter } from 'nodemailer';
|
import { TestAccount, Transporter } from 'nodemailer';
|
||||||
|
import Mail from 'nodemailer/lib/mailer';
|
||||||
|
import SMTPConnection from 'nodemailer/lib/smtp-connection';
|
||||||
|
|
||||||
|
export type BuildEmailResult = Promise<{
|
||||||
|
transport: Mail,
|
||||||
|
transportOptions?: SMTPConnection.Options,
|
||||||
|
fromName: string,
|
||||||
|
fromAddress: string,
|
||||||
|
}>
|
||||||
|
|
||||||
export type MockEmailHandler = { account: TestAccount; transport: Transporter };
|
export type MockEmailHandler = { account: TestAccount; transport: Transporter };
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import sanitizeFields from './sanitize';
|
import sanitizeFields from './sanitize';
|
||||||
import { MissingFieldType, InvalidFieldRelationship } from '../errors';
|
import { MissingFieldType, InvalidFieldRelationship } from '../../errors';
|
||||||
|
|
||||||
describe('sanitizeFields', () => {
|
describe('sanitizeFields', () => {
|
||||||
it('should throw on missing type field', () => {
|
it('should throw on missing type field', () => {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { MissingFieldType, InvalidFieldRelationship } from '../errors';
|
import { MissingFieldType, InvalidFieldRelationship } from '../../errors';
|
||||||
import validations from './validations';
|
import validations from '../validations';
|
||||||
|
|
||||||
const sanitizeFields = (fields, validRelationships) => {
|
const sanitizeFields = (fields, validRelationships) => {
|
||||||
if (!fields) return [];
|
if (!fields) return [];
|
||||||
30
src/fields/config/types.ts
Normal file
30
src/fields/config/types.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { CSSProperties } from 'react';
|
||||||
|
|
||||||
|
export type Field = {
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
type:
|
||||||
|
| 'number'
|
||||||
|
| 'text'
|
||||||
|
| 'email'
|
||||||
|
| 'textarea'
|
||||||
|
| 'richText'
|
||||||
|
| 'code'
|
||||||
|
| 'radio'
|
||||||
|
| 'checkbox'
|
||||||
|
| 'date'
|
||||||
|
| 'upload'
|
||||||
|
| 'relationship'
|
||||||
|
| 'row'
|
||||||
|
| 'array'
|
||||||
|
| 'group'
|
||||||
|
| 'select'
|
||||||
|
| 'blocks';
|
||||||
|
localized?: boolean;
|
||||||
|
fields?: Field[];
|
||||||
|
admin?: {
|
||||||
|
position?: string;
|
||||||
|
width?: string;
|
||||||
|
style?: CSSProperties;
|
||||||
|
};
|
||||||
|
};
|
||||||
0
src/globals/config/build.ts
Normal file
0
src/globals/config/build.ts
Normal file
@@ -1,5 +1,5 @@
|
|||||||
import { MissingGlobalLabel } from '../errors';
|
import { MissingGlobalLabel } from '../../errors';
|
||||||
import sanitizeFields from '../fields/sanitize';
|
import sanitizeFields from '../../fields/config/sanitize';
|
||||||
|
|
||||||
const sanitizeGlobals = (collections, globals) => {
|
const sanitizeGlobals = (collections, globals) => {
|
||||||
// /////////////////////////////////
|
// /////////////////////////////////
|
||||||
0
src/globals/config/types.ts
Normal file
0
src/globals/config/types.ts
Normal file
@@ -2,7 +2,7 @@
|
|||||||
* @jest-environment node
|
* @jest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import getConfig from '../../utilities/getConfig';
|
import getConfig from '../../config/load';
|
||||||
import { email, password } from '../../../tests/api/credentials';
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|||||||
101
src/index.ts
101
src/index.ts
@@ -1,11 +1,15 @@
|
|||||||
import express from 'express';
|
import express, { Express, Router } from 'express';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { Router } from 'express';
|
|
||||||
|
import { TestAccount } from 'nodemailer';
|
||||||
|
import {
|
||||||
|
Config,
|
||||||
|
InitOptions,
|
||||||
|
} from './config/types';
|
||||||
|
import {
|
||||||
|
Collection,
|
||||||
|
} from './collections/config/types';
|
||||||
import {
|
import {
|
||||||
PayloadConfig,
|
|
||||||
PayloadCollection,
|
|
||||||
PayloadInitOptions,
|
|
||||||
PayloadLogger,
|
|
||||||
CreateOptions,
|
CreateOptions,
|
||||||
FindOptions,
|
FindOptions,
|
||||||
FindGlobalOptions,
|
FindGlobalOptions,
|
||||||
@@ -18,7 +22,7 @@ import Logger from './utilities/logger';
|
|||||||
import bindOperations from './init/bindOperations';
|
import bindOperations from './init/bindOperations';
|
||||||
import bindRequestHandlers from './init/bindRequestHandlers';
|
import bindRequestHandlers from './init/bindRequestHandlers';
|
||||||
import bindResolvers from './init/bindResolvers';
|
import bindResolvers from './init/bindResolvers';
|
||||||
import getConfig from './utilities/getConfig';
|
import loadConfig from './config/load';
|
||||||
import authenticate from './express/middleware/authenticate';
|
import authenticate from './express/middleware/authenticate';
|
||||||
import connectMongoose from './mongoose/connect';
|
import connectMongoose from './mongoose/connect';
|
||||||
import expressMiddleware from './express/middleware';
|
import expressMiddleware from './express/middleware';
|
||||||
@@ -29,7 +33,6 @@ import initGlobals from './globals/init';
|
|||||||
import initGraphQLPlayground from './graphql/initPlayground';
|
import initGraphQLPlayground from './graphql/initPlayground';
|
||||||
import initStatic from './express/static';
|
import initStatic from './express/static';
|
||||||
import GraphQL from './graphql';
|
import GraphQL from './graphql';
|
||||||
import sanitizeConfig from './utilities/sanitizeConfig';
|
|
||||||
import buildEmail from './email/build';
|
import buildEmail from './email/build';
|
||||||
import identifyAPI from './express/middleware/identifyAPI';
|
import identifyAPI from './express/middleware/identifyAPI';
|
||||||
import errorHandler from './express/middleware/errorHandler';
|
import errorHandler from './express/middleware/errorHandler';
|
||||||
@@ -37,26 +40,58 @@ import performFieldOperations from './fields/performFieldOperations';
|
|||||||
import localOperations from './collections/operations/local';
|
import localOperations from './collections/operations/local';
|
||||||
import localGlobalOperations from './globals/operations/local';
|
import localGlobalOperations from './globals/operations/local';
|
||||||
import { encrypt, decrypt } from './auth/crypto';
|
import { encrypt, decrypt } from './auth/crypto';
|
||||||
import { TestAccount } from 'nodemailer';
|
import { MockEmailHandler, BuildEmailResult } from './email/types';
|
||||||
import { MockEmailHandler } from './email/types';
|
|
||||||
|
|
||||||
require('es6-promise').polyfill();
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|
||||||
class Payload {
|
class Payload {
|
||||||
config: PayloadConfig;
|
config: Config;
|
||||||
collections: PayloadCollection[] = [];
|
|
||||||
logger: PayloadLogger;
|
|
||||||
router: Router;
|
|
||||||
email: any;
|
|
||||||
|
|
||||||
init(options: PayloadInitOptions) {
|
collections: Collection[] = [];
|
||||||
|
|
||||||
|
logger: typeof Logger;
|
||||||
|
|
||||||
|
express: Express
|
||||||
|
|
||||||
|
router: Router;
|
||||||
|
|
||||||
|
emailOptions: any;
|
||||||
|
|
||||||
|
email: BuildEmailResult;
|
||||||
|
|
||||||
|
license: string;
|
||||||
|
|
||||||
|
secret: string;
|
||||||
|
|
||||||
|
mongoURL: string;
|
||||||
|
|
||||||
|
local: boolean;
|
||||||
|
|
||||||
|
initAuth: typeof initAuth;
|
||||||
|
|
||||||
|
encrypt: typeof encrypt;
|
||||||
|
|
||||||
|
decrypt: typeof decrypt;
|
||||||
|
|
||||||
|
initCollections: typeof initCollections;
|
||||||
|
|
||||||
|
initGlobals: typeof initGlobals;
|
||||||
|
|
||||||
|
initGraphQLPlayground: typeof initGraphQLPlayground;
|
||||||
|
|
||||||
|
initStatic: typeof initStatic;
|
||||||
|
|
||||||
|
initAdmin: typeof initAdmin;
|
||||||
|
|
||||||
|
performFieldOperations: typeof performFieldOperations;
|
||||||
|
|
||||||
|
init(options: InitOptions) {
|
||||||
this.logger = Logger();
|
this.logger = Logger();
|
||||||
this.logger.info('Starting Payload...');
|
this.logger.info('Starting Payload...');
|
||||||
|
|
||||||
if (!options.secret) {
|
if (!options.secret) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Error: missing secret key. A secret key is needed to secure Payload.'
|
'Error: missing secret key. A secret key is needed to secure Payload.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,21 +99,18 @@ class Payload {
|
|||||||
throw new Error('Error: missing MongoDB connection URL.');
|
throw new Error('Error: missing MongoDB connection URL.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = getConfig(options);
|
this.license = options.license;
|
||||||
const email = { ...(config.email || {}), ...(options.email || {}) };
|
this.emailOptions = { ...(options.email || {}) };
|
||||||
|
this.secret = crypto
|
||||||
this.config = sanitizeConfig({
|
|
||||||
...config,
|
|
||||||
email,
|
|
||||||
license: options.license,
|
|
||||||
secret: crypto
|
|
||||||
.createHash('sha256')
|
.createHash('sha256')
|
||||||
.update(options.secret)
|
.update(options.secret)
|
||||||
.digest('hex')
|
.digest('hex')
|
||||||
.slice(0, 32),
|
.slice(0, 32);
|
||||||
mongoURL: options.mongoURL,
|
|
||||||
local: options.local,
|
this.mongoURL = options.mongoURL;
|
||||||
});
|
this.local = options.local;
|
||||||
|
|
||||||
|
this.config = loadConfig();
|
||||||
|
|
||||||
if (typeof this.config.paths === 'undefined') this.config.paths = {};
|
if (typeof this.config.paths === 'undefined') this.config.paths = {};
|
||||||
|
|
||||||
@@ -121,14 +153,14 @@ class Payload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure email service
|
// Configure email service
|
||||||
this.email = buildEmail(this.config.email);
|
this.email = buildEmail(this.emailOptions);
|
||||||
|
|
||||||
// Initialize collections & globals
|
// Initialize collections & globals
|
||||||
this.initCollections();
|
this.initCollections();
|
||||||
this.initGlobals();
|
this.initGlobals();
|
||||||
|
|
||||||
// Connect to database
|
// Connect to database
|
||||||
connectMongoose(this.config.mongoURL);
|
connectMongoose(this.mongoURL);
|
||||||
|
|
||||||
options.express.use((req, res, next) => {
|
options.express.use((req, res, next) => {
|
||||||
req.payload = this;
|
req.payload = this;
|
||||||
@@ -138,8 +170,7 @@ class Payload {
|
|||||||
// If not initializing locally, set up HTTP routing
|
// If not initializing locally, set up HTTP routing
|
||||||
if (!this.config.local) {
|
if (!this.config.local) {
|
||||||
this.express = options.express;
|
this.express = options.express;
|
||||||
if (this.config.rateLimit && this.config.rateLimit.trustProxy)
|
if (this.config.rateLimit && this.config.rateLimit.trustProxy) { this.express.set('trust proxy', 1); }
|
||||||
this.express.set('trust proxy', 1);
|
|
||||||
|
|
||||||
this.initAdmin();
|
this.initAdmin();
|
||||||
|
|
||||||
@@ -150,7 +181,7 @@ class Payload {
|
|||||||
this.router.use(
|
this.router.use(
|
||||||
this.config.routes.graphQL,
|
this.config.routes.graphQL,
|
||||||
identifyAPI('GraphQL'),
|
identifyAPI('GraphQL'),
|
||||||
(req, res) => graphQLHandler.init(req, res)(req, res)
|
(req, res) => graphQLHandler.init(req, res)(req, res),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.initGraphQLPlayground();
|
this.initGraphQLPlayground();
|
||||||
|
|||||||
@@ -1,32 +1,3 @@
|
|||||||
// TODO: Split out init options from config types into own file
|
|
||||||
|
|
||||||
import { Express, Request } from 'express';
|
|
||||||
import { Transporter } from 'nodemailer';
|
|
||||||
import SMTPConnection from 'nodemailer/lib/smtp-connection';
|
|
||||||
import { Logger } from 'pino';
|
|
||||||
|
|
||||||
type MockEmailTransport = {
|
|
||||||
transport?: 'mock';
|
|
||||||
fromName?: string;
|
|
||||||
fromAddress?: string;
|
|
||||||
};
|
|
||||||
type ValidEmailTransport = {
|
|
||||||
transport: Transporter;
|
|
||||||
transportOptions?: SMTPConnection.Options;
|
|
||||||
fromName: string;
|
|
||||||
fromAddress: string;
|
|
||||||
};
|
|
||||||
export type PayloadEmailOptions = ValidEmailTransport | MockEmailTransport;
|
|
||||||
|
|
||||||
export type PayloadInitOptions = {
|
|
||||||
express?: Express;
|
|
||||||
mongoURL: string;
|
|
||||||
secret: string;
|
|
||||||
license?: string;
|
|
||||||
email?: PayloadEmailOptions;
|
|
||||||
local?: boolean; // I have no idea what this is
|
|
||||||
onInit?: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Document = {
|
export type Document = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -84,168 +55,3 @@ export type ForgotPasswordOptions = {
|
|||||||
expiration: Date;
|
expiration: Date;
|
||||||
data: any;
|
data: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SendEmailOptions = {
|
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
subject: string;
|
|
||||||
html: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MockEmailCredentials = {
|
|
||||||
user: string;
|
|
||||||
pass: string;
|
|
||||||
web: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PayloadField = {
|
|
||||||
name: string;
|
|
||||||
label: string;
|
|
||||||
type:
|
|
||||||
| 'number'
|
|
||||||
| 'text'
|
|
||||||
| 'email'
|
|
||||||
| 'textarea'
|
|
||||||
| 'richText'
|
|
||||||
| 'code'
|
|
||||||
| 'radio'
|
|
||||||
| 'checkbox'
|
|
||||||
| 'date'
|
|
||||||
| 'upload'
|
|
||||||
| 'relationship'
|
|
||||||
| 'row'
|
|
||||||
| 'array'
|
|
||||||
| 'group'
|
|
||||||
| 'select'
|
|
||||||
| 'blocks';
|
|
||||||
localized?: boolean;
|
|
||||||
fields?: PayloadField[];
|
|
||||||
admin?: {
|
|
||||||
position?: string;
|
|
||||||
width?: string;
|
|
||||||
style?: Object;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PayloadCollectionHook = (...args: any[]) => any | void;
|
|
||||||
export type PayloadAccess = (args?: any) => boolean;
|
|
||||||
|
|
||||||
export type PayloadCollection = {
|
|
||||||
slug: string;
|
|
||||||
labels?: {
|
|
||||||
singular: string;
|
|
||||||
plural: string;
|
|
||||||
};
|
|
||||||
admin?: {
|
|
||||||
useAsTitle?: string;
|
|
||||||
defaultColumns?: string[];
|
|
||||||
components?: any;
|
|
||||||
};
|
|
||||||
hooks?: {
|
|
||||||
beforeOperation?: PayloadCollectionHook[];
|
|
||||||
beforeValidate?: PayloadCollectionHook[];
|
|
||||||
beforeChange?: PayloadCollectionHook[];
|
|
||||||
afterChange?: PayloadCollectionHook[];
|
|
||||||
beforeRead?: PayloadCollectionHook[];
|
|
||||||
afterRead?: PayloadCollectionHook[];
|
|
||||||
beforeDelete?: PayloadCollectionHook[];
|
|
||||||
afterDelete?: PayloadCollectionHook[];
|
|
||||||
};
|
|
||||||
access?: {
|
|
||||||
create?: PayloadAccess;
|
|
||||||
read?: PayloadAccess;
|
|
||||||
update?: PayloadAccess;
|
|
||||||
delete?: PayloadAccess;
|
|
||||||
admin?: PayloadAccess;
|
|
||||||
};
|
|
||||||
auth?: {
|
|
||||||
tokenExpiration?: number;
|
|
||||||
verify?:
|
|
||||||
| boolean
|
|
||||||
| { generateEmailHTML: string; generateEmailSubject: string };
|
|
||||||
maxLoginAttempts?: number;
|
|
||||||
lockTime?: number;
|
|
||||||
useAPIKey?: boolean;
|
|
||||||
cookies?:
|
|
||||||
| {
|
|
||||||
secure?: boolean;
|
|
||||||
sameSite?: string;
|
|
||||||
domain?: string | undefined;
|
|
||||||
}
|
|
||||||
| boolean;
|
|
||||||
};
|
|
||||||
fields: PayloadField[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PayloadGlobal = {
|
|
||||||
slug: string;
|
|
||||||
label: string;
|
|
||||||
access?: {
|
|
||||||
create?: PayloadAccess;
|
|
||||||
read?: PayloadAccess;
|
|
||||||
update?: PayloadAccess;
|
|
||||||
delete?: PayloadAccess;
|
|
||||||
admin?: PayloadAccess;
|
|
||||||
};
|
|
||||||
fields: PayloadField[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PayloadConfig = {
|
|
||||||
admin?: {
|
|
||||||
user?: string;
|
|
||||||
meta?: {
|
|
||||||
titleSuffix?: string;
|
|
||||||
ogImage?: string;
|
|
||||||
favicon?: string;
|
|
||||||
};
|
|
||||||
disable?: boolean;
|
|
||||||
};
|
|
||||||
collections?: PayloadCollection[];
|
|
||||||
globals?: PayloadGlobal[];
|
|
||||||
serverURL?: string;
|
|
||||||
cookiePrefix?: string;
|
|
||||||
csrf?: string[];
|
|
||||||
cors?: string[];
|
|
||||||
publicENV: { [key: string]: string };
|
|
||||||
routes?: {
|
|
||||||
api?: string;
|
|
||||||
admin?: string;
|
|
||||||
graphQL?: string;
|
|
||||||
graphQLPlayground?: string;
|
|
||||||
};
|
|
||||||
email?: PayloadEmailOptions;
|
|
||||||
local?: boolean;
|
|
||||||
defaultDepth?: number;
|
|
||||||
maxDepth?: number;
|
|
||||||
rateLimit?: {
|
|
||||||
window?: number;
|
|
||||||
max?: number;
|
|
||||||
trustProxy?: boolean;
|
|
||||||
skip?: (req: Request) => boolean; // TODO: Type join Request w/ PayloadRequest
|
|
||||||
};
|
|
||||||
upload?: {
|
|
||||||
limits?: {
|
|
||||||
fileSize?: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
localization?: {
|
|
||||||
locales: string[];
|
|
||||||
};
|
|
||||||
defaultLocale?: string;
|
|
||||||
fallback?: boolean;
|
|
||||||
graphQL?: {
|
|
||||||
mutations?: Object;
|
|
||||||
queries?: Object;
|
|
||||||
maxComplexity?: number;
|
|
||||||
disablePlaygroundInProduction?: boolean;
|
|
||||||
};
|
|
||||||
components: { [key: string]: JSX.Element | (() => JSX.Element) };
|
|
||||||
paths?: { [key: string]: string };
|
|
||||||
hooks?: {
|
|
||||||
afterError?: () => void;
|
|
||||||
};
|
|
||||||
webpack?: (config: any) => any;
|
|
||||||
serverModules?: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PayloadLogger = Logger;
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import path from 'path';
|
|||||||
import MiniCSSExtractPlugin from 'mini-css-extract-plugin';
|
import MiniCSSExtractPlugin from 'mini-css-extract-plugin';
|
||||||
import TerserJSPlugin from 'terser-webpack-plugin';
|
import TerserJSPlugin from 'terser-webpack-plugin';
|
||||||
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
|
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
|
||||||
import babelConfig from '../babel.config';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
entry: {
|
entry: {
|
||||||
@@ -31,7 +30,6 @@ export default {
|
|||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
use: {
|
use: {
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: babelConfig,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
export default (cssOptions, preProcessor) => {
|
|
||||||
const loaders = [
|
|
||||||
'isomorphic-style-loader',
|
|
||||||
{
|
|
||||||
loader: require.resolve('css-loader'),
|
|
||||||
options: cssOptions,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Options for PostCSS as we reference these options twice
|
|
||||||
// Adds vendor prefixing based on your specified browser support in
|
|
||||||
// package.json
|
|
||||||
loader: require.resolve('postcss-loader'),
|
|
||||||
options: {
|
|
||||||
// Necessary for external CSS imports to work
|
|
||||||
// https://github.com/facebook/create-react-app/issues/2677
|
|
||||||
ident: 'postcss',
|
|
||||||
plugins: () => [
|
|
||||||
require('postcss-flexbugs-fixes'),
|
|
||||||
require('postcss-preset-env'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
if (preProcessor) {
|
|
||||||
loaders.push(require.resolve(preProcessor));
|
|
||||||
}
|
|
||||||
return loaders;
|
|
||||||
};
|
|
||||||
@@ -2,7 +2,6 @@ import HtmlWebpackPlugin from 'html-webpack-plugin';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import MiniCSSExtractPlugin from 'mini-css-extract-plugin';
|
import MiniCSSExtractPlugin from 'mini-css-extract-plugin';
|
||||||
import babelConfig from '../babel.config';
|
|
||||||
|
|
||||||
const mockModulePath = path.resolve(__dirname, '../mocks/emptyModule.js');
|
const mockModulePath = path.resolve(__dirname, '../mocks/emptyModule.js');
|
||||||
|
|
||||||
@@ -10,19 +9,19 @@ export default (config) => {
|
|||||||
let webpackConfig = {
|
let webpackConfig = {
|
||||||
entry: {
|
entry: {
|
||||||
main: [
|
main: [
|
||||||
"webpack-hot-middleware/client",
|
'webpack-hot-middleware/client',
|
||||||
path.resolve(__dirname, "../admin/index.tsx"),
|
path.resolve(__dirname, '../admin/index.tsx'),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: "/",
|
path: '/',
|
||||||
publicPath: config.routes.admin,
|
publicPath: config.routes.admin,
|
||||||
filename: "[name].js",
|
filename: '[name].js',
|
||||||
},
|
},
|
||||||
devtool: "inline-cheap-source-map",
|
devtool: 'inline-cheap-source-map',
|
||||||
mode: "development",
|
mode: 'development',
|
||||||
resolveLoader: {
|
resolveLoader: {
|
||||||
modules: ["node_modules", path.join(__dirname, "../../node_modules")],
|
modules: ['node_modules', path.join(__dirname, '../../node_modules')],
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
@@ -31,8 +30,7 @@ export default (config) => {
|
|||||||
exclude: /node_modules[\\/](?!(@payloadcms[\\/]payload)[\\/]).*/,
|
exclude: /node_modules[\\/](?!(@payloadcms[\\/]payload)[\\/]).*/,
|
||||||
use: [
|
use: [
|
||||||
{
|
{
|
||||||
loader: "babel-loader",
|
loader: 'babel-loader',
|
||||||
options: babelConfig,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -40,33 +38,33 @@ export default (config) => {
|
|||||||
oneOf: [
|
oneOf: [
|
||||||
{
|
{
|
||||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||||
loader: require.resolve("url-loader"),
|
loader: require.resolve('url-loader'),
|
||||||
options: {
|
options: {
|
||||||
limit: 10000,
|
limit: 10000,
|
||||||
name: "static/media/[name].[hash:8].[ext]",
|
name: 'static/media/[name].[hash:8].[ext]',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(sa|sc|c)ss$/,
|
test: /\.(sa|sc|c)ss$/,
|
||||||
use: [
|
use: [
|
||||||
MiniCSSExtractPlugin.loader,
|
MiniCSSExtractPlugin.loader,
|
||||||
"css-loader",
|
'css-loader',
|
||||||
{
|
{
|
||||||
loader: "postcss-loader",
|
loader: 'postcss-loader',
|
||||||
options: {
|
options: {
|
||||||
postcssOptions: {
|
postcssOptions: {
|
||||||
plugins: ["postcss-preset-env"],
|
plugins: ['postcss-preset-env'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"sass-loader",
|
'sass-loader',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
exclude: [/\.((t|j)s|(t|j)sx|mjs)$/, /\.html$/, /\.json$/],
|
exclude: [/\.((t|j)s|(t|j)sx|mjs)$/, /\.html$/, /\.json$/],
|
||||||
loader: require.resolve("file-loader"),
|
loader: require.resolve('file-loader'),
|
||||||
options: {
|
options: {
|
||||||
name: "static/media/[name].[hash:8].[ext]",
|
name: 'static/media/[name].[hash:8].[ext]',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -74,12 +72,12 @@ export default (config) => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: ["node_modules", path.resolve(__dirname, "../../node_modules")],
|
modules: ['node_modules', path.resolve(__dirname, '../../node_modules')],
|
||||||
alias: {
|
alias: {
|
||||||
"payload/unsanitizedConfig": config.paths.config,
|
'payload/unsanitizedConfig': config.paths.config,
|
||||||
"@payloadcms/payload$": mockModulePath,
|
'@payloadcms/payload$': mockModulePath,
|
||||||
},
|
},
|
||||||
extensions: [".ts", ".tsx", ".js", ".json"],
|
extensions: ['.ts', '.tsx', '.js', '.json'],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin(
|
new webpack.DefinePlugin(
|
||||||
@@ -88,15 +86,15 @@ export default (config) => {
|
|||||||
...values,
|
...values,
|
||||||
[`process.env.${key}`]: `'${val}'`,
|
[`process.env.${key}`]: `'${val}'`,
|
||||||
}),
|
}),
|
||||||
{}
|
{},
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template:
|
template:
|
||||||
config.admin && config.admin.indexHTML
|
config.admin && config.admin.indexHTML
|
||||||
? path.join(config.paths.configDir, config.admin.indexHTML)
|
? path.join(config.paths.configDir, config.admin.indexHTML)
|
||||||
: path.resolve(__dirname, "../admin/index.html"),
|
: path.resolve(__dirname, '../admin/index.html'),
|
||||||
filename: "./index.html",
|
filename: './index.html',
|
||||||
}),
|
}),
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
new MiniCSSExtractPlugin({
|
new MiniCSSExtractPlugin({
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
|
|||||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import babelConfig from '../babel.config';
|
|
||||||
|
|
||||||
const mockModulePath = path.resolve(__dirname, '../mocks/emptyModule.js');
|
const mockModulePath = path.resolve(__dirname, '../mocks/emptyModule.js');
|
||||||
|
|
||||||
@@ -44,7 +43,6 @@ export default (config) => {
|
|||||||
exclude: /node_modules[\\/](?!(@payloadcms[\\/]payload)[\\/]).*/,
|
exclude: /node_modules[\\/](?!(@payloadcms[\\/]payload)[\\/]).*/,
|
||||||
use: {
|
use: {
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: babelConfig,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user