merge ts-final

This commit is contained in:
Dan Ribbens
2020-11-29 15:39:54 -05:00
41 changed files with 400 additions and 284 deletions

View File

@@ -1,4 +1,5 @@
import React from 'react';
import Select from 'react-select';
import { Props } from './types';
import Chevron from '../../icons/Chevron';

View File

@@ -5,10 +5,10 @@ import { objectToFormData } from 'object-to-formdata';
import { useHistory } from 'react-router-dom';
import PropTypes from 'prop-types';
import { toast } from 'react-toastify';
import { useAuth } from '@payloadcms/config-provider';
import { useLocale } from '../../utilities/Locale';
import { requests } from '../../../api';
import useThrottledEffect from '../../../hooks/useThrottledEffect';
import { useAuth } from '@payloadcms/config-provider';
import fieldReducer from './fieldReducer';
import initContextState from './initContextState';
import reduceFieldsToValues from './reduceFieldsToValues';
@@ -24,7 +24,7 @@ import './index.scss';
const baseClass = 'form';
const Form = (props) => {
const Form: React.FC = (props) => {
const {
disabled,
onSubmit,

View File

@@ -1,7 +1,7 @@
import React, { createContext, useEffect, useContext, useState } from 'react';
import PropTypes from 'prop-types';
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
import useIntersect from '../../../hooks/useIntersect';
import { Props, Context } from './types';
const baseClass = 'render-fields';
@@ -9,11 +9,11 @@ const intersectionObserverOptions = {
rootMargin: '1000px',
};
const RenderedFieldContext = createContext({});
const RenderedFieldContext = createContext({} as Context);
export const useRenderedFields = () => useContext(RenderedFieldContext);
export const useRenderedFields = (): Context => useContext(RenderedFieldContext);
const RenderFields = (props) => {
const RenderFields: React.FC<Props> = (props) => {
const {
fieldSchema,
fieldTypes,
@@ -135,26 +135,4 @@ const RenderFields = (props) => {
return null;
};
RenderFields.defaultProps = {
filter: null,
readOnly: false,
permissions: {},
operation: undefined,
className: undefined,
};
RenderFields.propTypes = {
fieldSchema: PropTypes.arrayOf(
PropTypes.shape({}),
).isRequired,
fieldTypes: PropTypes.shape({
hidden: PropTypes.function,
}).isRequired,
filter: PropTypes.func,
permissions: PropTypes.shape({}),
readOnly: PropTypes.bool,
operation: PropTypes.string,
className: PropTypes.string,
};
export default RenderFields;

View File

@@ -0,0 +1,17 @@
import { CollectionPermission, GlobalPermission } from '../../../../auth/types';
import { Field } from '../../../../fields/config/types';
export type Operation = 'create' | 'update'
export type Context = {
operation: Operation
}
export type Props = {
className?: string
operation: Operation
readOnly: boolean
permissions: CollectionPermission | GlobalPermission
filter: (field: Field) => boolean
fieldSchema: Field[]
}

View File

@@ -2,14 +2,16 @@ import React, {
Component, useCallback,
} from 'react';
import PropTypes from 'prop-types';
import some from 'async-some';
import { useConfig } from '@payloadcms/config-provider';
import some from '../../../../../utilities/asyncSome';
import withCondition from '../../withCondition';
import ReactSelect from '../../../elements/ReactSelect';
import useFieldType from '../../useFieldType';
import Label from '../../Label';
import Error from '../../Error';
import { relationship } from '../../../../../fields/validations';
import { PaginatedDocs } from '../../../../../collections/config/types';
import { RelationshipProps, OptionsPage } from './types';
import './index.scss';
@@ -17,7 +19,7 @@ const maxResultsPerRequest = 10;
const baseClass = 'relationship';
class Relationship extends Component {
class Relationship extends Component<RelationshipProps> {
constructor(props) {
super(props);
@@ -77,7 +79,7 @@ class Relationship extends Component {
const fieldToSearch = collection?.admin?.useAsTitle || 'id';
const searchParam = search ? `&where[${fieldToSearch}][like]=${search}` : '';
const response = await fetch(`${serverURL}${api}/${relation}?limit=${maxResultsPerRequest}&page=${lastLoadedPage}${searchParam}`);
const data = await response.json();
const data: PaginatedDocs = await response.json();
if (response.ok) {
if (data.hasNextPage) {
@@ -87,7 +89,7 @@ class Relationship extends Component {
});
}
return callback({ relation, data });
return callback(true, { relation, data });
}
let error = 'There was a problem loading options for this field.';
@@ -99,7 +101,7 @@ class Relationship extends Component {
return this.setState({
errorLoading: error,
});
}, (lastPage, nextPage) => {
}, (lastPage: OptionsPage, nextPage: OptionsPage) => {
if (nextPage) {
const { data, relation } = nextPage;
this.addOptions(data, relation);

View File

@@ -0,0 +1,25 @@
import React from 'react';
import { PaginatedDocs } from '../../../../../collections/config/types';
import { Config } from '../../../../../config/types';
export type OptionsPage = {
relation: string
data: PaginatedDocs
}
export type RelationshipProps = {
required: boolean
errorMessage: string
hasMany: boolean
showError: boolean
value: unknown
path: string
formProcessing: boolean
admin: {
readOnly: boolean
style: React.CSSProperties
width: string
}
relationTo: string | string[]
config: Config
}

View File

@@ -1,20 +1,20 @@
import React from 'react';
import NavigationPrompt from 'react-router-navigation-prompt';
import { useAuth } from '@payloadcms/config-provider';
import { useFormModified } from '../../forms/Form/context';
import MinimalTemplate from '../../templates/Minimal';
import Button from '../../elements/Button';
import { useAuth } from '@payloadcms/config-provider';
import './index.scss';
const modalSlug = 'leave-without-saving';
const LeaveWithoutSaving = () => {
const LeaveWithoutSaving: React.FC = () => {
const modified = useFormModified();
const { user } = useAuth();
return (
<NavigationPrompt when={modified && user}>
<NavigationPrompt when={Boolean(modified && user)}>
{({ onConfirm, onCancel }) => (
<div className={modalSlug}>
<MinimalTemplate>

View File

@@ -5,12 +5,13 @@ import { useModal, Modal } from '@faceless-ui/modal';
import { useConfig } from '@payloadcms/config-provider';
import MinimalTemplate from '../../templates/Minimal';
import Button from '../../elements/Button';
import { Props } from './types';
import './index.scss';
const baseClass = 'stay-logged-in';
const StayLoggedInModal = (props) => {
const StayLoggedInModal: React.FC<Props> = (props) => {
const { refreshCookie } = props;
const history = useHistory();
const { routes: { admin } } = useConfig();

View File

@@ -0,0 +1,4 @@
export type Props = {
refreshCookie: () => void
}

View File

@@ -1,16 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
import DefaultNav from '../../elements/Nav';
import { useConfig } from '@payloadcms/config-provider';
import DefaultNav from '../../elements/Nav';
import { StepNavProvider } from '../../elements/StepNav';
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
import Meta from '../../utilities/Meta';
import { Props } from './types';
import './index.scss';
const baseClass = 'template-default';
const Default = ({ children, className }) => {
const Default: React.FC<Props> = ({ children, className }) => {
const {
admin: {
components: {
@@ -44,16 +44,4 @@ const Default = ({ children, className }) => {
);
};
Default.defaultProps = {
className: '',
};
Default.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
className: PropTypes.string,
};
export default Default;

View File

@@ -0,0 +1,3 @@
export type Props = {
className?: string,
};

View File

@@ -1,13 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Props } from './types';
import './index.scss';
const baseClass = 'template-minimal';
const Minimal = (props) => {
const Minimal: React.FC<Props> = (props) => {
const {
className, style, children, width,
className,
style = {},
children,
width = 'normal',
} = props;
const classes = [
@@ -28,17 +31,4 @@ const Minimal = (props) => {
);
};
Minimal.defaultProps = {
className: null,
style: {},
width: 'normal',
};
Minimal.propTypes = {
className: PropTypes.string,
style: PropTypes.shape({}),
children: PropTypes.node.isRequired,
width: PropTypes.oneOf(['normal', 'wide']),
};
export default Minimal;

View File

@@ -0,0 +1,7 @@
import React from 'react';
export type Props = {
className?: string,
width?: 'normal' | 'wide'
style?: React.CSSProperties
};

View File

@@ -5,17 +5,17 @@ import PropTypes from 'prop-types';
import { useConfig } from '@payloadcms/config-provider';
import { useSearchParams } from '../SearchParams';
const Context = createContext({});
const Context = createContext('');
export const LocaleProvider = ({ children }) => {
export const LocaleProvider: React.FC = ({ children }) => {
const { localization } = useConfig();
const defaultLocale = (localization && localization.defaultLocale) ? localization.defaultLocale : 'en';
const [locale, setLocale] = useState(defaultLocale);
const [locale, setLocale] = useState<string>(defaultLocale);
const searchParams = useSearchParams();
const localeFromParams = searchParams.locale;
useEffect(() => {
if (localeFromParams && localization.locales.indexOf(localeFromParams) > -1) setLocale(localeFromParams);
if (localeFromParams && localization.locales.indexOf(localeFromParams as string) > -1) setLocale(localeFromParams as string);
}, [localeFromParams, localization]);
return (
@@ -25,7 +25,7 @@ export const LocaleProvider = ({ children }) => {
);
};
export const useLocale = () => useContext(Context);
export const useLocale = (): string => useContext(Context);
LocaleProvider.propTypes = {
children: PropTypes.oneOfType([

View File

@@ -13,9 +13,9 @@ const Meta: React.FC<Props> = ({
keywords = 'CMS, Admin, Dashboard',
}) => {
const config = useConfig();
const titleSuffix = config?.admin?.meta?.titleSuffix ?? '- Payload';
const favicon = config?.admin?.meta?.favicon ?? payloadFavicon;
const ogImage = config?.admin?.meta?.ogImage ?? payloadOgImage;
const titleSuffix = config.admin.meta?.titleSuffix ?? '- Payload';
const favicon = config.admin.meta.favicon ?? payloadFavicon;
const ogImage = config.admin.meta.ogImage ?? payloadOgImage;
return (
<Helmet

View File

@@ -1,5 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
const Portal = ({ children }) => ReactDOM.createPortal(children, document.getElementById('portal'));
const Portal = ({ children }: { children: React.ReactNode}): React.ReactPortal => ReactDOM.createPortal(children, document.getElementById('portal'));
export default Portal;

View File

@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Props } from './types';
const RenderCustomComponent = (props) => {
const RenderCustomComponent: React.FC<Props> = (props) => {
const { CustomComponent, DefaultComponent, componentProps } = props;
if (CustomComponent) {
@@ -15,22 +15,4 @@ const RenderCustomComponent = (props) => {
);
};
RenderCustomComponent.defaultProps = {
path: undefined,
componentProps: {},
CustomComponent: null,
};
RenderCustomComponent.propTypes = {
path: PropTypes.string,
DefaultComponent: PropTypes.oneOfType([
PropTypes.shape({}),
PropTypes.func,
PropTypes.node,
PropTypes.element,
]).isRequired,
CustomComponent: PropTypes.func,
componentProps: PropTypes.shape({}),
};
export default RenderCustomComponent;

View File

@@ -0,0 +1,7 @@
import React from 'react';
export type Props = {
CustomComponent: React.ComponentType
DefaultComponent: React.ComponentType
componentProps?: unknown
}

View File

@@ -5,7 +5,7 @@ import qs from 'qs';
const Context = createContext({});
export const SearchParamsProvider = ({ children }) => {
export const SearchParamsProvider: React.FC = ({ children }) => {
const location = useLocation();
const params = qs.parse(
@@ -27,4 +27,4 @@ SearchParamsProvider.propTypes = {
]).isRequired,
};
export const useSearchParams = () => useContext(Context);
export const useSearchParams = (): qs.ParsedQs => useContext(Context);

View File

@@ -1,7 +1,7 @@
import { useState, useEffect } from 'react';
// Our hook
export default function useDebounce(value, delay) {
export default function useDebounce(value: unknown, delay: number): unknown {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState(value);

View File

@@ -1,8 +1,17 @@
/* eslint-disable no-shadow */
import { useEffect, useRef, useState } from 'react';
export default ({ root = null, rootMargin, threshold = 0 } = {}) => {
const [entry, updateEntry] = useState({});
type Intersect = [
setNode: React.Dispatch<Element>,
entry: IntersectionObserverEntry
]
const useIntersect = ({
root = null,
rootMargin = '0px',
threshold = 0,
} = {}): Intersect => {
const [entry, updateEntry] = useState<IntersectionObserverEntry>();
const [node, setNode] = useState(null);
const observer = useRef(
@@ -27,3 +36,5 @@ export default ({ root = null, rootMargin, threshold = 0 } = {}) => {
return [setNode, entry];
};
export default useIntersect;

View File

@@ -1,5 +1,5 @@
import { useEffect } from 'react';
const useMountEffect = func => useEffect(func, []);
const useMountEffect = (func: () => void): void => useEffect(func, []);
export default useMountEffect;

View File

@@ -3,11 +3,28 @@ import queryString from 'qs';
import { useLocale } from '../components/utilities/Locale';
import { requests } from '../api';
const usePayloadAPI = (url, options = {}) => {
type Result = [
{
isLoading: boolean
isError: boolean
data: unknown
},
{
setParams: React.Dispatch<unknown>
}
]
type Options = {
initialParams?: unknown
initialData?: unknown
}
type UsePayloadAPI = (url: string, options?: Options) => Result;
const usePayloadAPI: UsePayloadAPI = (url, options = {}) => {
const {
initialParams = {},
initialData = {},
onLoad,
} = options;
const [data, setData] = useState(initialData);
@@ -18,8 +35,8 @@ const usePayloadAPI = (url, options = {}) => {
const search = queryString.stringify({
locale,
...params,
}, { depth: 10 });
...(typeof params === 'object' ? params : {}),
});
useEffect(() => {
const fetchData = async () => {
@@ -48,7 +65,7 @@ const usePayloadAPI = (url, options = {}) => {
setIsError(false);
setIsLoading(false);
}
}, [url, locale, search, onLoad]);
}, [url, locale, search]);
return [{ data, isLoading, isError }, { setParams }];
};

View File

@@ -1,7 +1,9 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useRef } from 'react';
const useThrottledEffect = (callback, delay, deps = []) => {
type useThrottledEffect = (callback: React.EffectCallback, delay: number, deps: React.DependencyList) => void;
const useThrottledEffect: useThrottledEffect = (callback, delay, deps = []) => {
const lastRan = useRef(Date.now());
useEffect(

View File

@@ -1,6 +1,6 @@
import { useFormFields } from '../components/forms/Form/context';
const useTitle = (useAsTitle) => {
const useTitle = (useAsTitle: string): string => {
const { getField } = useFormFields();
const titleField = getField(useAsTitle);
return titleField?.value;

View File

@@ -1,6 +1,6 @@
import { useEffect } from 'react';
// eslint-disable-next-line react-hooks/exhaustive-deps
const useUnmountEffect = (callback) => useEffect(() => callback, []);
const useUnmountEffect = (callback: React.EffectCallback): void => useEffect(() => callback, []);
export default useUnmountEffect;

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable global-require */
/* eslint-disable import/no-dynamic-require */
@@ -5,14 +6,31 @@ import webpack from 'webpack';
import getWebpackProdConfig from '../webpack/getWebpackProdConfig';
import findConfig from '../config/find';
import loadConfig from '../config/load';
import { buildConfig } from '../config/build';
import getBabelConfig from '../babel.config';
const babelConfig = getBabelConfig({
env: () => false,
});
const configPath = findConfig();
const build = () => {
const build = (): void => {
try {
const unsanitizedConfig = loadConfig();
const config = buildConfig(unsanitizedConfig);
require('@babel/register')({
...babelConfig,
extensions: ['.js', '.jsx', '.ts', '.tsx'],
plugins: [
[
require('babel-plugin-ignore-html-and-css-imports'),
{
removeExtensions: ['.svg', '.css', '.scss', '.png', '.jpg'],
},
],
...babelConfig.plugins,
],
});
const config = loadConfig();
const webpackProdConfig = getWebpackProdConfig({
...config,

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env node
import minimist from 'minimist';
import build from './build';

View File

@@ -158,3 +158,16 @@ export type AfterForgotPasswordHook = (args?: {
}) => any;
export type AfterErrorHook = (args?: { [p: string]: any }, response?: any) => any;
export type PaginatedDocs = {
docs: unknown[]
totalDocs: number
limit: number
totalPages: number
page: number
pagingCounter: number
hasPrevPage: boolean
hasNextPage: boolean
prevPage: number | null
nextPage: number | null
}

View File

@@ -1,5 +1,5 @@
import path from 'path';
import fs from 'fs';
import findUp from 'find-up';
const findConfig = (): string => {
// If the developer has specified a config path,
@@ -12,30 +12,21 @@ const findConfig = (): string => {
return path.resolve(process.cwd(), process.env.PAYLOAD_CONFIG_PATH);
}
// By default, Payload is installed as a node_module.
// Traverse up three levels and check for config
const defaultPath = path.resolve(__dirname, '../../../payload.config.js');
const configPath = findUp.sync((dir) => {
const tsPath = path.join(dir, 'payload.config.ts');
const hasTS = findUp.sync.exists(tsPath);
if (fs.existsSync(defaultPath)) {
return defaultPath;
}
if (hasTS) return tsPath;
const defaultTSPath = path.resolve(__dirname, '../../../payload.config.ts');
const jsPath = path.join(dir, 'payload.config.js');
const hasJS = findUp.sync.exists(jsPath);
if (fs.existsSync(defaultTSPath)) {
return defaultTSPath;
}
if (hasJS) return jsPath;
// Check for config in current working directory
const cwdJSPath = path.resolve(process.cwd(), 'payload.config.js');
if (fs.existsSync(cwdJSPath)) {
return cwdJSPath;
}
return undefined;
});
const cwdTSPath = path.resolve(process.cwd(), 'payload.config.ts');
if (fs.existsSync(cwdTSPath)) {
return cwdTSPath;
}
if (configPath) return configPath;
throw new Error('Error: cannot find Payload config. Please create a configuration file located at the root of your current working directory called "payload.config.js" or "payload.config.ts".');
};

View File

@@ -57,6 +57,9 @@ export type PayloadConfig = {
}
disable?: boolean;
indexHTML?: string;
components?: {
Nav: React.ComponentType
}
};
collections?: PayloadCollectionConfig[];
globals?: Global[];
@@ -93,7 +96,8 @@ export type PayloadConfig = {
};
};
localization?: {
locales: string[];
locales: string[]
defaultLocale: string
};
defaultLocale?: string;
fallback?: boolean;

View File

@@ -39,7 +39,7 @@ type FieldBase = {
readOnly?: boolean;
disabled?: boolean;
condition?: (...args: any[]) => any | void;
components?: { [key: string]: JSX.Element | (() => JSX.Element) };
components?: { [key: string]: React.ComponentType };
};
access?: {
create?: Access;
@@ -52,6 +52,7 @@ type FieldBase = {
}
export type StandardField = FieldBase & {
type: string;
fields?: Field[];
}
@@ -120,6 +121,7 @@ export type RadioField = FieldBase & {
value: string;
label: string;
}[];
hasMany?: boolean;
}
export type Block = {
@@ -135,23 +137,16 @@ export type BlockField = FieldBase & {
type: 'blocks';
minRows?: number;
maxRows?: number;
blocks?: Block[];
blocks?: Field[];
};
export type Field = NumberField
| TextField
| EmailField
| TextareaField
| CodeField
| CheckboxField
| DateField
export type Field =
| StandardField
| BlockField
| RadioField
| RelationshipField
| ArrayField
| RichTextField
| GroupField
| RowField
| SelectField
| SelectManyField
| UploadField;

View File

@@ -1,15 +1,17 @@
/* eslint-disable no-use-before-define */
import { Schema } from 'mongoose';
import { MissingFieldInputOptions } from '../errors';
import { ArrayField, BlockField, CheckboxField, CodeField, DateField, EmailField, Field, GroupField, NumberField, RadioField, RelationshipField, RichTextField, RowField, SelectField, TextareaField, TextField, UploadField } from '../fields/config/types';
import { ArrayField, BlockField, Field, RadioField, RelationshipField, SelectField, StandardField, UploadField } from '../fields/config/types';
const setBlockDiscriminators = (fields: Field[], schema) => {
fields.forEach((field) => {
if (field.type === 'blocks' && field.blocks && field.blocks.length > 0) {
field.blocks.forEach((block) => {
const blockFieldType = field as BlockField;
if (blockFieldType.type === 'blocks' && blockFieldType.blocks && blockFieldType.blocks.length > 0) {
blockFieldType.blocks.forEach((blockItem: StandardField) => {
let blockSchemaFields = {};
block.fields.forEach((blockField) => {
// TODO: Would this blow up on a relationship since it doesn't have fields?
blockItem.fields.forEach((blockField) => {
const fieldSchema = fieldToSchemaMap[blockField.type];
if (fieldSchema) {
blockSchemaFields = fieldSchema(blockField, blockSchemaFields);
@@ -17,9 +19,9 @@ const setBlockDiscriminators = (fields: Field[], schema) => {
});
const blockSchema = new Schema(blockSchemaFields, { _id: false });
schema.path(field.name).discriminator(block.slug, blockSchema);
schema.path(field.name).discriminator(blockItem.slug, blockSchema);
setBlockDiscriminators(block.fields, blockSchema);
setBlockDiscriminators(blockItem.fields, blockSchema);
});
}
});
@@ -58,27 +60,27 @@ const buildSchema = (configFields: Field[], options = {}): Schema => {
};
const fieldToSchemaMap = {
number: (field: NumberField, fields: Field[]) => ({
number: (field: Field, fields: Field[]) => ({
...fields,
[field.name]: { ...formatBaseSchema(field), type: Number },
}),
text: (field: TextField, fields: Field[]) => ({
text: (field: Field, fields: Field[]) => ({
...fields,
[field.name]: { ...formatBaseSchema(field), type: String },
}),
email: (field: EmailField, fields: Field[]) => ({
email: (field: Field, fields: Field[]) => ({
...fields,
[field.name]: { ...formatBaseSchema(field), type: String },
}),
textarea: (field: TextareaField, fields: Field[]) => ({
textarea: (field: Field, fields: Field[]) => ({
...fields,
[field.name]: { ...formatBaseSchema(field), type: String },
}),
richText: (field: RichTextField, fields: Field[]) => ({
richText: (field: Field, fields: Field[]) => ({
...fields,
[field.name]: { ...formatBaseSchema(field), type: Schema.Types.Mixed },
}),
code: (field: CodeField, fields: Field[]) => ({
code: (field: Field, fields: Field[]) => ({
...fields,
[field.name]: { ...formatBaseSchema(field), type: String },
}),
@@ -101,11 +103,11 @@ const fieldToSchemaMap = {
[field.name]: field.hasMany ? [schema] : schema, // TODO: radio group with hasMany??
};
},
checkbox: (field: CheckboxField, fields: Field[]) => ({
checkbox: (field: Field, fields: Field[]) => ({
...fields,
[field.name]: { ...formatBaseSchema(field), type: Boolean },
}),
date: (field: DateField, fields: Field[]) => ({
date: (field: Field, fields: Field[]) => ({
...fields,
[field.name]: { ...formatBaseSchema(field), type: Date },
}),
@@ -147,10 +149,10 @@ const fieldToSchemaMap = {
[field.name]: schema,
};
},
row: (field: RowField, fields: Field[]) => {
row: (field: StandardField, fields: Field[]) => {
const newFields = { ...fields };
field.fields.forEach((rowField) => {
field.fields.forEach((rowField: Field) => {
const fieldSchemaMap = fieldToSchemaMap[rowField.type];
if (fieldSchemaMap) {
@@ -172,7 +174,7 @@ const fieldToSchemaMap = {
},
};
},
group: (field: GroupField, fields: Field[]) => {
group: (field: StandardField, fields: Field[]) => {
const schema = buildSchema(field.fields, { _id: false, id: false });
return {

View File

@@ -1,22 +0,0 @@
declare module '*.svg' {
import React = require('react');
export const ReactComponent: React.SFC<React.SVGProps<SVGSVGElement>>;
const src: string;
export default src;
}
declare module '*.jpg' {
const content: string;
export default content;
}
declare module '*.png' {
const content: string;
export default content;
}
declare module '*.json' {
const content: string;
export default content;
}

View File

@@ -0,0 +1,56 @@
/* eslint-disable no-use-before-define */
/* eslint-disable consistent-return */
import wrappy from 'wrappy';
import asap from 'asap';
type Reduce = (er: boolean, result: unknown) => void;
type Callback = (last: unknown, next: unknown) => void;
const ensureFutureTick = wrappy((cb: Callback) => {
let sync = true;
asap(() => {
sync = false;
});
return function safe(...args: unknown[]) {
if (sync) {
asap(() => {
cb.apply(this, args);
});
} else { cb.apply(this, args); }
};
});
function some(list: unknown[], predicate: (item: unknown, reduce: Reduce) => void, cb: Callback): void {
const array = slice(list);
let index = 0;
const { length } = array;
const hecomes = ensureFutureTick(cb);
const reduce: Reduce = (er, result) => {
if (er) return hecomes(er, false);
if (result) return hecomes(null, result);
index += 1;
map();
};
map();
function map() {
if (index >= length) return hecomes(null, false);
predicate(array[index], reduce);
}
}
function slice(args: unknown[]) {
const l = args.length;
const a = [];
let i: number;
for (i = 0; i < l; i += 1) a[i] = args[i];
return a;
}
export default some;

View File

@@ -74,7 +74,6 @@ export default (config: PayloadConfig): Configuration => {
crypto: false,
https: false,
http: false,
assert: false,
},
modules: ['node_modules', path.resolve(__dirname, '../../node_modules')],
alias: {

View File

@@ -1,14 +1,14 @@
import HtmlWebpackPlugin from 'html-webpack-plugin';
import TerserJSPlugin from 'terser-webpack-plugin';
import MiniCSSExtractPlugin from 'mini-css-extract-plugin';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import path from 'path';
import webpack, { Configuration } from 'webpack';
import { Config } from '../config/types';
import babelConfig from '../babel.config';
const mockModulePath = path.resolve(__dirname, '../mocks/emptyModule.js');
const mockModulePath = path.resolve(__dirname, './mocks/emptyModule.js');
export default (config: Config): Configuration => {
let webpackConfig: Configuration = {
@@ -25,7 +25,7 @@ export default (config: Config): Configuration => {
devtool: 'source-map',
stats: 'errors-only',
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
minimizer: [new TerserJSPlugin({}), new CssMinimizerPlugin()],
splitChunks: {
cacheGroups: {
styles: {
@@ -41,53 +41,40 @@ export default (config: Config): Configuration => {
module: {
rules: [
{
test: /\.js$/,
test: /\.(t|j|)sx?$/,
exclude: /node_modules[\\/](?!(@payloadcms[\\/]payload)[\\/]).*/,
use: {
loader: require.resolve('babel-loader'),
options: babelConfig({ env: () => false }),
},
},
{
test: /\.(sa|sc|c)ss$/,
sideEffects: true,
use: [
MiniCSSExtractPlugin.loader,
require.resolve('css-loader'),
{
loader: require.resolve('postcss-loader'),
options: {
postcssOptions: {
plugins: [require.resolve('postcss-preset-env')],
},
},
},
require.resolve('sass-loader'),
],
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
type: 'asset/resource',
},
{
test: /\.(sa|sc|c)ss$/,
sideEffects: true,
use: [
MiniCSSExtractPlugin.loader,
require.resolve('css-loader'),
{
loader: require.resolve('postcss-loader'),
options: {
postcssOptions: {
plugins: [
[
require.resolve('postcss-preset-env'),
{
// Options
},
],
],
},
},
},
require.resolve('sass-loader'),
],
},
{
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
type: 'asset/inline',
},
],
},
@@ -99,20 +86,23 @@ export default (config: Config): Configuration => {
crypto: false,
https: false,
http: false,
assert: false,
},
modules: ['node_modules', path.resolve(__dirname, '../../node_modules')],
alias: {
'payload/config': config.paths.config,
'@payloadcms/payload$': mockModulePath,
},
extensions: ['.ts', '.tsx', '.js', '.json'],
},
plugins: [
new webpack.ProvidePlugin(
{ process: 'process/browser' },
),
new HtmlWebpackPlugin({
template: config.admin && config.admin.indexHTML
? path.join(config.paths.configDir, config.admin.indexHTML)
: path.resolve(__dirname, '../admin/index.html'),
filename: './index.html',
filename: path.normalize('./index.html'),
}),
new webpack.DefinePlugin(Object.entries(config.publicENV).reduce((values, [key, val]) => ({
...values,
@@ -142,7 +132,7 @@ export default (config: Config): Configuration => {
}
if (config.webpack && typeof config.webpack === 'function') {
webpackConfig = config.webpack(webpackConfig, 'production');
webpackConfig = config.webpack(webpackConfig);
}
return webpackConfig;