use webpack for all builds

This commit is contained in:
Shawn Erquhart 2018-07-17 19:13:52 -04:00
parent 040dd6859c
commit 2f95d8c4fc
96 changed files with 2886 additions and 2068 deletions

View File

@ -1,57 +0,0 @@
{
"presets": [
"react",
["env", {
"modules": false,
}],
],
"plugins": [
"lodash",
["babel-plugin-transform-builtin-extend", {
"globals": ["Error"]
}],
["transform-runtime", {
"useBuiltIns": true,
"useESModules": true,
}],
["module-resolver", {
"root": [
"./src/components"
],
"alias": {
"Actions": "./src/actions/",
"Backends": "./src/backends/",
"Constants": "./src/constants/",
"Formats": "./src/formats/",
"Integrations": "./src/integrations/",
"Lib": "./src/lib/",
"Reducers": "./src/reducers/",
"Redux": "./src/redux/",
"Routing": "./src/routing/",
"ValueObjects": "./src/valueObjects/",
}
}],
"transform-export-extensions",
"transform-class-properties",
"transform-object-rest-spread",
["inline-svg", {
"svgo": {
"plugins": [
{"removeViewBox": false},
],
},
}],
],
"env": {
"production": {
"plugins": [
["emotion", {"hoist": true}],
],
},
"development": {
"plugins": [
["emotion", {"sourceMap": true, "autoLabel": true }],
],
},
},
}

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ manifest.yml
website/data/contributors.json
/coverage/
.cache
*.log

54
babel.config.js Normal file
View File

@ -0,0 +1,54 @@
module.exports = {
presets: [
'@babel/preset-react',
['@babel/preset-env', {
modules: false,
}],
],
plugins: [
'lodash',
['babel-plugin-transform-builtin-extend', {
globals: ['Error']
}],
['module-resolver', {
root: [
'./src/components'
],
alias: {
Actions: './src/actions/',
Backends: './src/backends/',
Constants: './src/constants/',
Formats: './src/formats/',
Integrations: './src/integrations/',
Lib: './src/lib/',
Reducers: './src/reducers/',
Redux: './src/redux/',
Routing: './src/routing/',
ValueObjects: './src/valueObjects/',
}
}],
'transform-export-extensions',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-export-default-from',
['inline-svg', {
svgo: {
plugins: [
{removeViewBox: false},
],
},
}],
],
env: {
production: {
plugins: [
['emotion', {hoist: true}],
],
},
development: {
plugins: [
['emotion', {sourceMap: true, autoLabel: true}],
],
},
},
};

View File

@ -17,9 +17,11 @@
"pre-commit": "lint:staged",
"scripts": {
"bootstrap": "lerna bootstrap && lerna link --force-local",
"start": "yarn bootstrap && yarn watch",
"start": "npm run bootstrap && npm run watch",
"watch": "lerna run watch --parallel",
"clean": "cd packages && rimraf */.cache */*.js */*.css */*.svg */*.map"
"build": "npm run clean && cross-env NODE_ENV=production lerna run build",
"clean": "rimraf packages/*/dist",
"reset": "npm run clean && lerna clean --yes"
},
"jest": {
"moduleNameMapper": {
@ -58,6 +60,11 @@
"last 2 ChromeAndroid versions"
],
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.0.0-beta.54",
"@babel/plugin-proposal-export-default-from": "^7.0.0-beta.54",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.54",
"@babel/preset-env": "^7.0.0-beta.54",
"@babel/preset-react": "^7.0.0-beta.54",
"all-contributors-cli": "^4.4.0",
"babel-plugin-emotion": "^9.2.4",
"babel-plugin-inline-import": "^3.0.0",
@ -65,13 +72,8 @@
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-module-resolver": "^3.0.0",
"babel-plugin-transform-builtin-extend": "^1.1.2",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-export-extensions": "^6.22.0",
"babel-plugin-transform-inline-environment-variables": "^0.4.3",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.23.0",
"cross-env": "^5.1.4",
"deep-equal": "^1.0.1",
"enzyme": "^3.1.0",
@ -84,10 +86,14 @@
"postcss-loader": "^2.1.3",
"raf": "^3.4.0",
"react-test-renderer": "^16.0.0",
"rimraf": "^2.6.2"
"rimraf": "^2.6.2",
"rollup-plugin-babel": "^3.0.7"
},
"workspaces": [
"packages/*"
],
"private": true
"private": true,
"dependencies": {
"friendly-errors-webpack-plugin": "^1.7.0"
}
}

View File

@ -0,0 +1,3 @@
const config = require('../../babel.config.js');
module.exports = config;

View File

@ -3,28 +3,38 @@
"description": "GitHub backend for Netlify CMS",
"version": "2.0.0-alpha.0",
"license": "MIT",
"main": "dist/netlify-cms-backend-github.js",
"keywords": [
"netlify",
"netlify-cms",
"backend",
"github"
],
"sideEffects": false,
"scripts": {
"watch": "parcel watch src/*.js --out-dir . --no-cache",
"build": "parcel build src/*.js --out-dir . --no-cache"
"watch": "webpack -w",
"build": "cross-env NODE_ENV=production webpack"
},
"dependencies": {
"js-base64": "^2.4.8",
"lodash": "^4.17.10",
"netlify-cms-lib-auth": "file:../netlify-cms-lib-auth",
"netlify-cms-lib-util": "file:../netlify-cms-lib-util",
"netlify-cms-ui-default": "file:../netlify-cms-ui-default",
"prop-types": "^15.6.2",
"react": "^16.4.1",
"react-emotion": "^9.2.6",
"semaphore": "^1.1.0"
},
"devDependencies": {
"parcel-bundler": "^1.9.4"
"@babel/cli": "^7.0.0-beta.54",
"@babel/core": "^7.0.0-beta.54",
"cross-env": "^5.2.0",
"rollup": "^0.63.2",
"rollup-plugin-babel": "^4.0.0-beta.7",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0"
},
"peerDependencies": {
"netlify-cms-lib-auth": "2.0.0-alpha.0",
"netlify-cms-lib-util": "2.0.0-alpha.0",
"netlify-cms-ui-default": "2.0.0-alpha.0",
"lodash": "^4.17.10",
"prop-types": "^15.6.2",
"react": "^16.4.1",
"react-emotion": "^9.2.6"
}
}

View File

@ -1,9 +1,8 @@
import localForage from "netlify-cms-lib-util/localForage";
import { localForage } from "netlify-cms-lib-util";
import { Base64 } from "js-base64";
import { uniq, initial, last, get, find, hasIn, partial } from "lodash";
import { filterPromises, resolvePromiseProperties } from "netlify-cms-lib-util/promise";
import APIError from "netlify-cms-lib-util/APIError";
import EditorialWorkflowError from "netlify-cms-lib-util/EditorialWorkflowError";
import { filterPromises, resolvePromiseProperties } from "netlify-cms-lib-util";
import { APIError, EditorialWorkflowError } from "netlify-cms-lib-util";
const CMS_BRANCH_PREFIX = 'cms/';

View File

@ -1,9 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'react-emotion';
import Authenticator from 'netlify-cms-lib-auth/netlify-auth';
import Icon from 'netlify-cms-ui-default/Icon';
import { buttons, shadows } from 'netlify-cms-ui-default/styles';
import { NetlifyAuthenticator } from 'netlify-cms-lib-auth';
import { Icon, buttons, shadows } from 'netlify-cms-ui-default';
const StyledAuthenticationPage = styled.section`
display: flex;
@ -53,7 +52,7 @@ export default class AuthenticationPage extends React.Component {
site_id: (document.location.host.split(':')[0] === 'localhost') ? 'cms.netlify.com' : this.props.siteId,
auth_endpoint: this.props.authEndpoint,
};
const auth = new Authenticator(cfg);
const auth = new NetlifyAuthenticator(cfg);
auth.authenticate({ provider: 'github', scope: 'repo' }, (err, data) => {
if (err) {

View File

@ -0,0 +1,197 @@
import trimStart from 'lodash/trimStart';
import semaphore from "semaphore";
import AuthenticationPage from "./AuthenticationPage";
import API from "./API";
const MAX_CONCURRENT_DOWNLOADS = 10;
export default class GitHub {
constructor(config, options={}) {
this.config = config;
this.options = {
proxied: false,
API: null,
...options,
};
if (!this.options.proxied && config.getIn(["backend", "repo"]) == null) {
throw new Error("The GitHub backend needs a \"repo\" in the backend configuration.");
}
this.api = this.options.API || null;
this.repo = config.getIn(["backend", "repo"], "");
this.branch = config.getIn(["backend", "branch"], "master").trim();
this.api_root = config.getIn(["backend", "api_root"], "https://api.github.com");
this.token = '';
this.squash_merges = config.getIn(["backend", "squash_merges"]);
}
authComponent() {
return AuthenticationPage;
}
restoreUser(user) {
return this.authenticate(user);
}
authenticate(state) {
this.token = state.token;
this.api = new API({ token: this.token, branch: this.branch, repo: this.repo, api_root: this.api_root, squash_merges: this.squash_merges });
return this.api.user().then(user =>
this.api.hasWriteAccess().then((isCollab) => {
// Unauthorized user
if (!isCollab) throw new Error("Your GitHub user account does not have access to this repo.");
// Authorized user
user.token = state.token;
return user;
})
);
}
logout() {
this.token = null;
return;
}
getToken() {
return Promise.resolve(this.token);
}
entriesByFolder(collection, extension) {
return this.api.listFiles(collection.get("folder"))
.then(files => files.filter(file => file.name.endsWith('.' + extension)))
.then(this.fetchFiles);
}
entriesByFiles(collection) {
const files = collection.get("files").map(collectionFile => ({
path: collectionFile.get("file"),
label: collectionFile.get("label"),
}));
return this.fetchFiles(files);
}
fetchFiles = (files) => {
const sem = semaphore(MAX_CONCURRENT_DOWNLOADS);
const promises = [];
files.forEach((file) => {
promises.push(new Promise((resolve, reject) => (
sem.take(() => this.api.readFile(file.path, file.sha).then((data) => {
resolve({ file, data });
sem.leave();
}).catch((err = true) => {
sem.leave();
console.error(`failed to load file from GitHub: ${file.path}`);
resolve({ error: err });
}))
)));
});
return Promise.all(promises)
.then(loadedEntries => loadedEntries.filter(loadedEntry => !loadedEntry.error));
};
// Fetches a single entry.
getEntry(collection, slug, path) {
return this.api.readFile(path).then(data => ({
file: { path },
data,
}));
}
getMedia() {
return this.api.listFiles(this.config.get('media_folder'))
.then(files => files.map(({ sha, name, size, download_url, path }) => {
const url = new URL(download_url);
if (url.pathname.match(/.svg$/)) {
url.search += (url.search.slice(1) === '' ? '?' : '&') + 'sanitize=true';
}
return { id: sha, name, size, url: url.href, path };
}));
}
persistEntry(entry, mediaFiles = [], options = {}) {
return this.api.persistFiles(entry, mediaFiles, options);
}
async persistMedia(mediaFile, options = {}) {
try {
const response = await this.api.persistFiles(null, [mediaFile], options);
const { sha, value, size, path, fileObj } = mediaFile;
const url = URL.createObjectURL(fileObj);
return { id: sha, name: value, size: fileObj.size, url, path: trimStart(path, '/') };
}
catch(error) {
console.error(error);
throw error;
}
}
deleteFile(path, commitMessage, options) {
return this.api.deleteFile(path, commitMessage, options);
}
unpublishedEntries() {
return this.api.listUnpublishedBranches().then((branches) => {
const sem = semaphore(MAX_CONCURRENT_DOWNLOADS);
const promises = [];
branches.map((branch) => {
promises.push(new Promise((resolve, reject) => {
const slug = branch.ref.split("refs/heads/cms/").pop();
return sem.take(() => this.api.readUnpublishedBranchFile(slug).then((data) => {
if (data === null || data === undefined) {
resolve(null);
sem.leave();
} else {
const path = data.metaData.objects.entry.path;
resolve({
slug,
file: { path },
data: data.fileData,
metaData: data.metaData,
isModification: data.isModification,
});
sem.leave();
}
}).catch((err) => {
sem.leave();
resolve(null);
}));
}));
});
return Promise.all(promises);
})
.catch((error) => {
if (error.message === "Not Found") {
return Promise.resolve([]);
}
return error;
});
}
unpublishedEntry(collection, slug) {
return this.api.readUnpublishedBranchFile(slug)
.then((data) => {
if (!data) return null;
return {
slug,
file: { path: data.metaData.objects.entry.path },
data: data.fileData,
metaData: data.metaData,
isModification: data.isModification,
};
});
}
updateUnpublishedEntryStatus(collection, slug, newStatus) {
return this.api.updateUnpublishedEntryStatus(collection, slug, newStatus);
}
deleteUnpublishedEntry(collection, slug) {
return this.api.deleteUnpublishedEntry(collection, slug);
}
publishUnpublishedEntry(collection, slug) {
return this.api.publishUnpublishedEntry(collection, slug);
}
}

View File

@ -1,197 +1,4 @@
import trimStart from 'lodash/trimStart';
import semaphore from "semaphore";
import AuthenticationPage from "./AuthenticationPage";
import API from "./API";
export GitHubBackend from './implementation';
export API from './API';
export AuthenticationPage from './AuthenticationPage';
const MAX_CONCURRENT_DOWNLOADS = 10;
export default class GitHub {
constructor(config, options={}) {
this.config = config;
this.options = {
proxied: false,
API: null,
...options,
};
if (!this.options.proxied && config.getIn(["backend", "repo"]) == null) {
throw new Error("The GitHub backend needs a \"repo\" in the backend configuration.");
}
this.api = this.options.API || null;
this.repo = config.getIn(["backend", "repo"], "");
this.branch = config.getIn(["backend", "branch"], "master").trim();
this.api_root = config.getIn(["backend", "api_root"], "https://api.github.com");
this.token = '';
this.squash_merges = config.getIn(["backend", "squash_merges"]);
}
authComponent() {
return AuthenticationPage;
}
restoreUser(user) {
return this.authenticate(user);
}
authenticate(state) {
this.token = state.token;
this.api = new API({ token: this.token, branch: this.branch, repo: this.repo, api_root: this.api_root, squash_merges: this.squash_merges });
return this.api.user().then(user =>
this.api.hasWriteAccess().then((isCollab) => {
// Unauthorized user
if (!isCollab) throw new Error("Your GitHub user account does not have access to this repo.");
// Authorized user
user.token = state.token;
return user;
})
);
}
logout() {
this.token = null;
return;
}
getToken() {
return Promise.resolve(this.token);
}
entriesByFolder(collection, extension) {
return this.api.listFiles(collection.get("folder"))
.then(files => files.filter(file => file.name.endsWith('.' + extension)))
.then(this.fetchFiles);
}
entriesByFiles(collection) {
const files = collection.get("files").map(collectionFile => ({
path: collectionFile.get("file"),
label: collectionFile.get("label"),
}));
return this.fetchFiles(files);
}
fetchFiles = (files) => {
const sem = semaphore(MAX_CONCURRENT_DOWNLOADS);
const promises = [];
files.forEach((file) => {
promises.push(new Promise((resolve, reject) => (
sem.take(() => this.api.readFile(file.path, file.sha).then((data) => {
resolve({ file, data });
sem.leave();
}).catch((err = true) => {
sem.leave();
console.error(`failed to load file from GitHub: ${file.path}`);
resolve({ error: err });
}))
)));
});
return Promise.all(promises)
.then(loadedEntries => loadedEntries.filter(loadedEntry => !loadedEntry.error));
};
// Fetches a single entry.
getEntry(collection, slug, path) {
return this.api.readFile(path).then(data => ({
file: { path },
data,
}));
}
getMedia() {
return this.api.listFiles(this.config.get('media_folder'))
.then(files => files.map(({ sha, name, size, download_url, path }) => {
const url = new URL(download_url);
if (url.pathname.match(/.svg$/)) {
url.search += (url.search.slice(1) === '' ? '?' : '&') + 'sanitize=true';
}
return { id: sha, name, size, url: url.href, path };
}));
}
persistEntry(entry, mediaFiles = [], options = {}) {
return this.api.persistFiles(entry, mediaFiles, options);
}
async persistMedia(mediaFile, options = {}) {
try {
const response = await this.api.persistFiles(null, [mediaFile], options);
const { sha, value, size, path, fileObj } = mediaFile;
const url = URL.createObjectURL(fileObj);
return { id: sha, name: value, size: fileObj.size, url, path: trimStart(path, '/') };
}
catch(error) {
console.error(error);
throw error;
}
}
deleteFile(path, commitMessage, options) {
return this.api.deleteFile(path, commitMessage, options);
}
unpublishedEntries() {
return this.api.listUnpublishedBranches().then((branches) => {
const sem = semaphore(MAX_CONCURRENT_DOWNLOADS);
const promises = [];
branches.map((branch) => {
promises.push(new Promise((resolve, reject) => {
const slug = branch.ref.split("refs/heads/cms/").pop();
return sem.take(() => this.api.readUnpublishedBranchFile(slug).then((data) => {
if (data === null || data === undefined) {
resolve(null);
sem.leave();
} else {
const path = data.metaData.objects.entry.path;
resolve({
slug,
file: { path },
data: data.fileData,
metaData: data.metaData,
isModification: data.isModification,
});
sem.leave();
}
}).catch((err) => {
sem.leave();
resolve(null);
}));
}));
});
return Promise.all(promises);
})
.catch((error) => {
if (error.message === "Not Found") {
return Promise.resolve([]);
}
return error;
});
}
unpublishedEntry(collection, slug) {
return this.api.readUnpublishedBranchFile(slug)
.then((data) => {
if (!data) return null;
return {
slug,
file: { path: data.metaData.objects.entry.path },
data: data.fileData,
metaData: data.metaData,
isModification: data.isModification,
};
});
}
updateUnpublishedEntryStatus(collection, slug, newStatus) {
return this.api.updateUnpublishedEntryStatus(collection, slug, newStatus);
}
deleteUnpublishedEntry(collection, slug) {
return this.api.deleteUnpublishedEntry(collection, slug);
}
publishUnpublishedEntry(collection, slug) {
return this.api.publishUnpublishedEntry(collection, slug);
}
}

View File

@ -0,0 +1 @@
module.exports = require('../../webpack.config.js');

View File

@ -0,0 +1,3 @@
const config = require('../../babel.config.js');
module.exports = config;

View File

@ -3,28 +3,37 @@
"description": "Development testing backend for Netlify CMS",
"version": "2.0.0-alpha.0",
"license": "MIT",
"main": "dist/netlify-cms-backend-test.js",
"keywords": [
"netlify",
"netlify-cms",
"backend"
],
"sideEffects": false,
"scripts": {
"watch": "parcel watch src/*.js --out-dir . --no-cache",
"build": "parcel build src/*.js --out-dir . --no-cache"
"watch": "webpack -w",
"build": "cross-env NODE_ENV=production webpack"
},
"dependencies": {
"immutable": "^3.8.2",
"lodash": "^4.17.10",
"netlify": "^1.2.0",
"netlify-cms-lib-util": "file:../netlify-cms-lib-util",
"netlify-cms-ui-default": "file:../netlify-cms-ui-default",
"prop-types": "^15.6.2",
"react": "^16.4.1",
"react-emotion": "^9.2.6",
"react-immutable-proptypes": "^2.1.0",
"uuid": "^3.3.2"
},
"devDependencies": {
"parcel-bundler": "^1.9.4"
"@babel/cli": "^7.0.0-beta.54",
"@babel/core": "^7.0.0-beta.54",
"cross-env": "^5.2.0",
"rollup": "^0.63.2",
"rollup-plugin-babel": "^4.0.0-beta.7",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0"
},
"peerDependencies": {
"immutable": "^3.8.2",
"lodash": "^4.17.10",
"netlify-cms-lib-util": "2.0.0-alpha.0",
"netlify-cms-ui-default": "2.0.0-alpha.0",
"prop-types": "^15.6.2",
"react": "^16.4.1",
"react-emotion": "^9.2.6",
"react-immutable-proptypes": "^2.1.0"
}
}

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Icon from 'netlify-cms-ui-default/Icon';
import { Icon } from 'netlify-cms-ui-default';
export default class AuthenticationPage extends React.Component {
static propTypes = {

View File

@ -0,0 +1,225 @@
import { fromJS } from 'immutable';
import { remove, attempt, isError, take } from 'lodash';
import uuid from 'uuid/v4';
import { EditorialWorkflowError } from 'netlify-cms-lib-util';
import { Cursor, CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util';
import AuthenticationPage from './AuthenticationPage';
window.repoFiles = window.repoFiles || {};
window.repoFilesUnpublished = window.repoFilesUnpublished || [];
function getFile(path) {
const segments = path.split('/');
let obj = window.repoFiles;
while (obj && segments.length) {
obj = obj[segments.shift()];
}
return obj || {};
}
const pageSize = 10;
const getCursor = (collection, extension, entries, index) => {
const count = entries.length;
const pageCount = Math.floor(count / pageSize);
return Cursor.create({
actions: [
...(index < pageCount ? ["next", "last"] : []),
...(index > 0 ? ["prev", "first"] : []),
],
meta: { index, count, pageSize, pageCount },
data: { collection, extension, index, pageCount },
});
};
const getFolderEntries = (folder, extension) => {
return Object.keys(window.repoFiles[folder] || {})
.filter(path => path.endsWith(`.${ extension }`))
.map(path => ({
file: { path: `${ folder }/${ path }` },
data: window.repoFiles[folder][path].content,
}))
.reverse();
};
export default class TestRepo {
constructor(config) {
this.config = config;
this.assets = [];
this.initialStatus = config.initialStatus;
}
authComponent() {
return AuthenticationPage;
}
restoreUser(user) {
return this.authenticate(user);
}
authenticate() {
return Promise.resolve();
}
logout() {
return null;
}
getToken() {
return Promise.resolve('');
}
traverseCursor(cursor, action) {
const { collection, extension, index, pageCount } = cursor.data.toObject();
const newIndex = (() => {
if (action === "next") { return index + 1; }
if (action === "prev") { return index - 1; }
if (action === "first") { return 0; }
if (action === "last") { return pageCount; }
})();
// TODO: stop assuming cursors are for collections
const allEntries = getFolderEntries(collection.get('folder'), extension);
const entries = allEntries.slice(newIndex * pageSize, (newIndex * pageSize) + pageSize);
const newCursor = getCursor(collection, extension, allEntries, newIndex);
return Promise.resolve({ entries, cursor: newCursor });
}
entriesByFolder(collection, extension) {
const folder = collection.get('folder');
const entries = folder ? getFolderEntries(folder, extension) : [];
const cursor = getCursor(collection, extension, entries, 0);
const ret = take(entries, pageSize);
ret[CURSOR_COMPATIBILITY_SYMBOL] = cursor;
return Promise.resolve(ret);
}
entriesByFiles(collection) {
const files = collection.get('files').map(collectionFile => ({
path: collectionFile.get('file'),
label: collectionFile.get('label'),
}));
return Promise.all(files.map(file => ({
file,
data: getFile(file.path).content,
})));
}
getEntry(collection, slug, path) {
return Promise.resolve({
file: { path },
data: getFile(path).content,
});
}
unpublishedEntries() {
return Promise.resolve(window.repoFilesUnpublished);
}
unpublishedEntry(collection, slug) {
const entry = window.repoFilesUnpublished.find(e => (
e.metaData.collection === collection.get('name') && e.slug === slug
));
if (!entry) {
return Promise.reject(new EditorialWorkflowError('content is not under editorial workflow', true));
}
return Promise.resolve(entry);
}
deleteUnpublishedEntry(collection, slug) {
const unpubStore = window.repoFilesUnpublished;
const existingEntryIndex = unpubStore.findIndex(e => (
e.metaData.collection === collection && e.slug === slug
));
unpubStore.splice(existingEntryIndex, 1);
return Promise.resolve();
}
persistEntry({ path, raw, slug }, mediaFiles = [], options = {}) {
if (options.useWorkflow) {
const unpubStore = window.repoFilesUnpublished;
const existingEntryIndex = unpubStore.findIndex(e => e.file.path === path);
if (existingEntryIndex >= 0) {
const unpubEntry = { ...unpubStore[existingEntryIndex], data: raw };
unpubEntry.title = options.parsedData && options.parsedData.title;
unpubEntry.description = options.parsedData && options.parsedData.description;
unpubStore.splice(existingEntryIndex, 1, unpubEntry);
} else {
const unpubEntry = {
data: raw,
file: {
path,
},
metaData: {
collection: options.collectionName,
status: this.initialStatus,
title: options.parsedData && options.parsedData.title,
description: options.parsedData && options.parsedData.description,
},
slug,
};
unpubStore.push(unpubEntry);
}
return Promise.resolve();
}
const newEntry = options.newEntry || false;
const folder = path.substring(0, path.lastIndexOf('/'));
const fileName = path.substring(path.lastIndexOf('/') + 1);
window.repoFiles[folder] = window.repoFiles[folder] || {};
window.repoFiles[folder][fileName] = window.repoFiles[folder][fileName] || {};
if (newEntry) {
window.repoFiles[folder][fileName] = { content: raw };
} else {
window.repoFiles[folder][fileName].content = raw;
}
return Promise.resolve();
}
updateUnpublishedEntryStatus(collection, slug, newStatus) {
const unpubStore = window.repoFilesUnpublished;
const entryIndex = unpubStore.findIndex(e => (
e.metaData.collection === collection && e.slug === slug
));
unpubStore[entryIndex].metaData.status = newStatus;
return Promise.resolve();
}
publishUnpublishedEntry(collection, slug) {
const unpubStore = window.repoFilesUnpublished;
const unpubEntryIndex = unpubStore.findIndex(e => (
e.metaData.collection === collection && e.slug === slug
));
const unpubEntry = unpubStore[unpubEntryIndex];
const entry = { raw: unpubEntry.data, slug: unpubEntry.slug, path: unpubEntry.file.path };
unpubStore.splice(unpubEntryIndex, 1);
return this.persistEntry(entry);
}
getMedia() {
return Promise.resolve(this.assets);
}
persistMedia({ fileObj }) {
const { name, size } = fileObj;
const objectUrl = attempt(window.URL.createObjectURL, fileObj);
const url = isError(objectUrl) ? '' : objectUrl;
const normalizedAsset = { id: uuid(), name, size, path: url, url };
this.assets.push(normalizedAsset);
return Promise.resolve(normalizedAsset);
}
deleteFile(path, commitMessage) {
const assetIndex = this.assets.findIndex(asset => asset.path === path);
if (assetIndex > -1) {
this.assets.splice(assetIndex, 1);
}
else {
const folder = path.substring(0, path.lastIndexOf('/'));
const fileName = path.substring(path.lastIndexOf('/') + 1);
delete window.repoFiles[folder][fileName];
}
return Promise.resolve();
}
}

View File

@ -1,225 +1,2 @@
import { fromJS } from 'immutable';
import { remove, attempt, isError, take } from 'lodash';
import uuid from 'uuid/v4';
import EditorialWorkflowError from 'netlify-cms-lib-util/EditorialWorkflowError';
import Cursor, { CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util/Cursor'
import AuthenticationPage from './AuthenticationPage';
window.repoFiles = window.repoFiles || {};
window.repoFilesUnpublished = window.repoFilesUnpublished || [];
function getFile(path) {
const segments = path.split('/');
let obj = window.repoFiles;
while (obj && segments.length) {
obj = obj[segments.shift()];
}
return obj || {};
}
const pageSize = 10;
const getCursor = (collection, extension, entries, index) => {
const count = entries.length;
const pageCount = Math.floor(count / pageSize);
return Cursor.create({
actions: [
...(index < pageCount ? ["next", "last"] : []),
...(index > 0 ? ["prev", "first"] : []),
],
meta: { index, count, pageSize, pageCount },
data: { collection, extension, index, pageCount },
});
};
const getFolderEntries = (folder, extension) => {
return Object.keys(window.repoFiles[folder] || {})
.filter(path => path.endsWith(`.${ extension }`))
.map(path => ({
file: { path: `${ folder }/${ path }` },
data: window.repoFiles[folder][path].content,
}))
.reverse();
};
export default class TestRepo {
constructor(config) {
this.config = config;
this.assets = [];
this.initialStatus = config.initialStatus;
}
authComponent() {
return AuthenticationPage;
}
restoreUser(user) {
return this.authenticate(user);
}
authenticate() {
return Promise.resolve();
}
logout() {
return null;
}
getToken() {
return Promise.resolve('');
}
traverseCursor(cursor, action) {
const { collection, extension, index, pageCount } = cursor.data.toObject();
const newIndex = (() => {
if (action === "next") { return index + 1; }
if (action === "prev") { return index - 1; }
if (action === "first") { return 0; }
if (action === "last") { return pageCount; }
})();
// TODO: stop assuming cursors are for collections
const allEntries = getFolderEntries(collection.get('folder'), extension);
const entries = allEntries.slice(newIndex * pageSize, (newIndex * pageSize) + pageSize);
const newCursor = getCursor(collection, extension, allEntries, newIndex);
return Promise.resolve({ entries, cursor: newCursor });
}
entriesByFolder(collection, extension) {
const folder = collection.get('folder');
const entries = folder ? getFolderEntries(folder, extension) : [];
const cursor = getCursor(collection, extension, entries, 0);
const ret = take(entries, pageSize);
ret[CURSOR_COMPATIBILITY_SYMBOL] = cursor;
return Promise.resolve(ret);
}
entriesByFiles(collection) {
const files = collection.get('files').map(collectionFile => ({
path: collectionFile.get('file'),
label: collectionFile.get('label'),
}));
return Promise.all(files.map(file => ({
file,
data: getFile(file.path).content,
})));
}
getEntry(collection, slug, path) {
return Promise.resolve({
file: { path },
data: getFile(path).content,
});
}
unpublishedEntries() {
return Promise.resolve(window.repoFilesUnpublished);
}
unpublishedEntry(collection, slug) {
const entry = window.repoFilesUnpublished.find(e => (
e.metaData.collection === collection.get('name') && e.slug === slug
));
if (!entry) {
return Promise.reject(new EditorialWorkflowError('content is not under editorial workflow', true));
}
return Promise.resolve(entry);
}
deleteUnpublishedEntry(collection, slug) {
const unpubStore = window.repoFilesUnpublished;
const existingEntryIndex = unpubStore.findIndex(e => (
e.metaData.collection === collection && e.slug === slug
));
unpubStore.splice(existingEntryIndex, 1);
return Promise.resolve();
}
persistEntry({ path, raw, slug }, mediaFiles = [], options = {}) {
if (options.useWorkflow) {
const unpubStore = window.repoFilesUnpublished;
const existingEntryIndex = unpubStore.findIndex(e => e.file.path === path);
if (existingEntryIndex >= 0) {
const unpubEntry = { ...unpubStore[existingEntryIndex], data: raw };
unpubEntry.title = options.parsedData && options.parsedData.title;
unpubEntry.description = options.parsedData && options.parsedData.description;
unpubStore.splice(existingEntryIndex, 1, unpubEntry);
} else {
const unpubEntry = {
data: raw,
file: {
path,
},
metaData: {
collection: options.collectionName,
status: this.initialStatus,
title: options.parsedData && options.parsedData.title,
description: options.parsedData && options.parsedData.description,
},
slug,
};
unpubStore.push(unpubEntry);
}
return Promise.resolve();
}
const newEntry = options.newEntry || false;
const folder = path.substring(0, path.lastIndexOf('/'));
const fileName = path.substring(path.lastIndexOf('/') + 1);
window.repoFiles[folder] = window.repoFiles[folder] || {};
window.repoFiles[folder][fileName] = window.repoFiles[folder][fileName] || {};
if (newEntry) {
window.repoFiles[folder][fileName] = { content: raw };
} else {
window.repoFiles[folder][fileName].content = raw;
}
return Promise.resolve();
}
updateUnpublishedEntryStatus(collection, slug, newStatus) {
const unpubStore = window.repoFilesUnpublished;
const entryIndex = unpubStore.findIndex(e => (
e.metaData.collection === collection && e.slug === slug
));
unpubStore[entryIndex].metaData.status = newStatus;
return Promise.resolve();
}
publishUnpublishedEntry(collection, slug) {
const unpubStore = window.repoFilesUnpublished;
const unpubEntryIndex = unpubStore.findIndex(e => (
e.metaData.collection === collection && e.slug === slug
));
const unpubEntry = unpubStore[unpubEntryIndex];
const entry = { raw: unpubEntry.data, slug: unpubEntry.slug, path: unpubEntry.file.path };
unpubStore.splice(unpubEntryIndex, 1);
return this.persistEntry(entry);
}
getMedia() {
return Promise.resolve(this.assets);
}
persistMedia({ fileObj }) {
const { name, size } = fileObj;
const objectUrl = attempt(window.URL.createObjectURL, fileObj);
const url = isError(objectUrl) ? '' : objectUrl;
const normalizedAsset = { id: uuid(), name, size, path: url, url };
this.assets.push(normalizedAsset);
return Promise.resolve(normalizedAsset);
}
deleteFile(path, commitMessage) {
const assetIndex = this.assets.findIndex(asset => asset.path === path);
if (assetIndex > -1) {
this.assets.splice(assetIndex, 1);
}
else {
const folder = path.substring(0, path.lastIndexOf('/'));
const fileName = path.substring(path.lastIndexOf('/') + 1);
delete window.repoFiles[folder][fileName];
}
return Promise.resolve();
}
}
export TestBackend from './implementation';
export AuthenticationPage from './AuthenticationPage';

View File

@ -0,0 +1 @@
module.exports = require('../../webpack.config.js');

View File

@ -0,0 +1,3 @@
const config = require('../../babel.config.js');
module.exports = config;

View File

@ -1,4 +0,0 @@
import { init } from '../src/index';
import config from './config.yml';
init({ config });

View File

@ -1,5 +1,6 @@
backend:
name: test-repo
name: github
repo: erquhart/blank
display_url: https://example.com
media_folder: "assets/uploads"

View File

@ -5,10 +5,7 @@
<title>Netlify CMS Development Test</title>
<link rel="stylesheet" href="../src/index.css"/>
<script>
window.CMS_MANUAL_INIT = true;
window.repoFiles = {
_posts: {
"2015-02-14-this-is-a-post.md": {
@ -82,7 +79,7 @@
</head>
<body>
<script src='cms-test.js'></script>
<script src="dist/netlify-cms-core.js"></script>
<script>
var PostPreview = createClass({
render: function() {

View File

@ -2,7 +2,7 @@
"name": "netlify-cms-core",
"description": "Netlify CMS lets content editors work on structured content stored in git",
"version": "2.0.0-alpha.0",
"main": "dist/cms.js",
"main": "dist/netlify-cms-core.js",
"lint-staged": {
"*.js": [
"eslint --fix",
@ -15,8 +15,8 @@
"dist/"
],
"scripts": {
"watch": "cross-env NETLIFY_CMS_VERSION=$npm_package_version parcel example/index.html --no-cache --open",
"build": "cross-env NETLIFY_CMS_VERSION=$npm_package_version parcel build example/index.html --no-cache "
"watch": "cross-env NETLIFY_CMS_VERSION=$npm_package_version webpack-dev-server --hot --open",
"build": "cross-env NETLIFY_CMS_VERSION=$npm_package_version webpack"
},
"keywords": [
"netlify",
@ -46,10 +46,10 @@
"mdast-util-definitions": "^1.2.2",
"mdast-util-to-string": "^1.0.4",
"moment": "^2.11.2",
"netlify-cms-editor-component-image": "file:../netlify-cms-editor-component-image",
"netlify-cms-lib-auth": "file:../netlify-cms-lib-auth",
"netlify-cms-lib-util": "file:../netlify-cms-lib-util",
"netlify-cms-ui-default": "file:../netlify-cms-ui-default",
"netlify-cms-editor-component-image": "2.0.0-alpha.0",
"netlify-cms-lib-auth": "2.0.0-alpha.0",
"netlify-cms-lib-util": "2.0.0-alpha.0",
"netlify-cms-ui-default": "2.0.0-alpha.0",
"prop-types": "^15.5.10",
"react": "^16.4.1",
"react-aria-menubutton": "^5.1.0",
@ -104,7 +104,11 @@
"what-input": "^5.0.3"
},
"devDependencies": {
"@babel/core": "^7.0.0-beta.54",
"babel-loader": "^8.0.0-beta",
"cross-env": "^5.2.0",
"parcel-bundler": "^1.9.4"
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.4"
}
}

View File

@ -6,7 +6,7 @@ import { currentBackend } from 'Backends/backend';
import { getAsset } from 'Reducers';
import { selectFields } from 'Reducers/collections';
import { status, EDITORIAL_WORKFLOW } from 'Constants/publishModes';
import EditorialWorkflowError from 'netlify-cms-lib-util/EditorialWorkflowError';
import { EditorialWorkflowError } from 'netlify-cms-lib-util';
import { loadEntry } from './entries';
import ValidationErrorTypes from 'Constants/validationErrorTypes';

View File

@ -6,7 +6,7 @@ import { getIntegrationProvider } from 'Integrations';
import { getAsset, selectIntegration } from 'Reducers';
import { selectFields } from 'Reducers/collections';
import { selectCollectionEntriesCursor } from 'Reducers/cursors';
import Cursor from 'netlify-cms-lib-util/Cursor'
import { Cursor } from 'netlify-cms-lib-util';
import { createEntry } from 'ValueObjects/Entry';
import ValidationErrorTypes from 'Constants/validationErrorTypes';
import isArray from 'lodash/isArray';

View File

@ -1,8 +1,8 @@
import { attempt, flatten, isError } from 'lodash';
import { fromJS, Map } from 'immutable';
import fuzzy from 'fuzzy';
import GitHubBackend from "netlify-cms-backend-github";
import TestRepoBackend from "netlify-cms-backend-test";
import { GitHubBackend } from "netlify-cms-backend-github";
import { TestBackend } from "netlify-cms-backend-test";
import { resolveFormat } from "Formats/formats";
import { selectIntegration } from 'Reducers/integrations';
import {
@ -21,7 +21,7 @@ import GitLabBackend from "./gitlab/implementation";
import BitBucketBackend from "./bitbucket/implementation";
import GitGatewayBackend from "./git-gateway/implementation";
import { registerBackend, getBackend } from 'Lib/registry';
import Cursor, { CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util/Cursor'
import { Cursor, CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util';
import { EDITORIAL_WORKFLOW, status } from 'Constants/publishModes';
/**
@ -31,7 +31,7 @@ registerBackend('git-gateway', GitGatewayBackend);
registerBackend('github', GitHubBackend);
registerBackend('gitlab', GitLabBackend);
registerBackend('bitbucket', BitBucketBackend);
registerBackend('test-repo', TestRepoBackend);
registerBackend('test-repo', TestBackend);
class LocalStorageAuthStore {

View File

@ -1,5 +1,5 @@
import GithubAPI from "netlify-cms-backend-github/API";
import APIError from "netlify-cms-lib-util/APIError";
import { API as GithubAPI } from "netlify-cms-backend-github";
import { APIError } from "netlify-cms-lib-util";
export default class API extends GithubAPI {
constructor(config) {

View File

@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from "react";
import { partial } from 'lodash';
import Icon from 'netlify-cms-ui-default/Icon';
import { Icon } from 'netlify-cms-ui-default';
let component = null;

View File

@ -1,5 +1,5 @@
import GithubAPI from "netlify-cms-backend-github/API";
import APIError from "netlify-cms-lib-util/APIError";
import { API as GithubAPI } from "netlify-cms-backend-github";
import { APIError } from "netlify-cms-lib-util";
export default class API extends GithubAPI {
constructor(config) {

View File

@ -1,6 +1,5 @@
import { flow } from "lodash";
import unsentRequest from "netlify-cms-lib-util/unsentRequest";
import { then } from "netlify-cms-lib-util/promise";
import { unsentRequest, then } from "netlify-cms-lib-util";
import GitlabAPI from "Backends/gitlab/API";
export default class API extends GitlabAPI {

View File

@ -3,7 +3,7 @@ import jwtDecode from 'jwt-decode';
import {List} from 'immutable';
import { get, pick, intersection } from "lodash";
import { unsentRequest } from "netlify-cms-lib-util";
import GitHubBackend from "netlify-cms-backend-github";
import { GitHubBackend } from "netlify-cms-backend-github";
import GitLabBackend from "Backends/gitlab/implementation";
import BitBucketBackend from "Backends/bitbucket/implementation";
import GitHubAPI from "./GitHubAPI";

View File

@ -1,11 +1,7 @@
import localForage from "netlify-cms-lib-util/localForage";
import { localForage, unsentRequest, then, APIError, Cursor } from "netlify-cms-lib-util";
import { Base64 } from "js-base64";
import { fromJS, List, Map } from "immutable";
import { cond, flow, isString, partial, partialRight, pick, omit, set, update, get } from "lodash";
import unsentRequest from "netlify-cms-lib-util/unsentRequest";
import { then } from "netlify-cms-lib-util/promise";
import APIError from "netlify-cms-lib-util/APIError";
import Cursor from 'netlify-cms-lib-util/Cursor'
import AssetProxy from "ValueObjects/AssetProxy";
export default class API {

View File

@ -1,8 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import NetlifyAuthenticator from 'netlify-cms-lib-auth/netlify-auth';
import ImplicitAuthenticator from 'netlify-cms-lib-auth/implicit-oauth';
import Icon from 'netlify-cms-ui-default/Icon';
import PropTypes from 'prop-types';
import { NetlifyAuthenticator, ImplicitAuthenticator } from 'netlify-cms-lib-auth';
import { Icon } from 'netlify-cms-ui-default';
export default class AuthenticationPage extends React.Component {
static propTypes = {

View File

@ -1,7 +1,6 @@
import trimStart from 'lodash/trimStart';
import semaphore from "semaphore";
import { fileExtension } from 'netlify-cms-lib-util/path';
import Cursor, { CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util/Cursor'
import { fileExtension, Cursor, CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util';
import AuthenticationPage from "./AuthenticationPage";
import API from "./API";
import { EDITORIAL_WORKFLOW } from "Constants/publishModes";

View File

@ -11,7 +11,6 @@ import { ErrorBoundary } from 'UI'
import App from 'App/App';
import 'EditorWidgets';
import 'MarkdownPlugins';
import './index.css';
import 'what-input';
const ROOT_ID = 'nc-root';

View File

@ -14,8 +14,7 @@ import { showCollection, createNewEntry } from 'Actions/collections';
import { openMediaLibrary as actionOpenMediaLibrary } from 'Actions/mediaLibrary';
import MediaLibrary from 'MediaLibrary/MediaLibrary';
import { Toast } from 'UI';
import Loader from 'netlify-cms-ui-default/Loader';
import { colors } from 'netlify-cms-ui-default/styles';
import { Loader, colors } from 'netlify-cms-ui-default';
import history from 'Routing/history';
import { getCollectionUrl, getNewEntryUrl } from 'Lib/urlHelper';
import { SIMPLE, EDITORIAL_WORKFLOW } from 'Constants/publishModes';

View File

@ -4,9 +4,17 @@ import ImmutablePropTypes from "react-immutable-proptypes";
import styled, { css } from 'react-emotion';
import { NavLink } from 'react-router-dom';
import uuid from 'uuid/v4';
import Icon from 'netlify-cms-ui-default/Icon';
import Dropdown, { DropdownItem, StyledDropdownButton } from 'netlify-cms-ui-default/Dropdown'
import { colors, colorsRaw, lengths, shadows, buttons } from 'netlify-cms-ui-default/styles'
import {
Icon,
Dropdown,
DropdownItem,
StyledDropdownButton,
colors,
colorsRaw,
lengths,
shadows,
buttons,
} from 'netlify-cms-ui-default';
import SettingsDropdown from 'UI/SettingsDropdown';
const styles = {
@ -132,7 +140,7 @@ export default class Header extends React.Component {
</AppHeaderNavLink>
{
hasWorkflow
? <AppHeaderNavLink to="/workflow" activeClassName={this.activeClassName}>
? <AppHeaderNavLink to="/workflow" activeClassName={Header.activeClassName}>
<Icon type="workflow"/>
Workflow
</AppHeaderNavLink>

View File

@ -1,6 +1,6 @@
import React from 'react';
import styled from 'react-emotion';
import { lengths } from 'netlify-cms-ui-default/styles';
import { lengths } from 'netlify-cms-ui-default';
const NotFoundContainer = styled.div`

View File

@ -2,7 +2,7 @@ import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import styled from 'react-emotion';
import { connect } from 'react-redux';
import { lengths } from 'netlify-cms-ui-default/styles';
import { lengths } from 'netlify-cms-ui-default';
import { getNewEntryUrl } from 'Lib/urlHelper';
import Sidebar from './Sidebar';
import CollectionTop from './CollectionTop';

View File

@ -2,8 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import styled from 'react-emotion';
import { Link } from 'react-router-dom';
import Icon from 'netlify-cms-ui-default/Icon';
import { components, buttons, shadows, colors } from 'netlify-cms-ui-default/styles';
import { Icon, components, buttons, shadows, colors } from 'netlify-cms-ui-default';
import { VIEW_STYLE_LIST, VIEW_STYLE_GRID } from 'Constants/collectionViews';
const CollectionTopContainer = styled.div`

View File

@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Loader from 'netlify-cms-ui-default/Loader';
import { Loader } from 'netlify-cms-ui-default';
import EntryListing from './EntryListing';
const Entries = ({

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { partial } from 'lodash';
import Cursor from 'netlify-cms-lib-util/Cursor'
import { Cursor } from 'netlify-cms-lib-util'
import {
loadEntries as actionLoadEntries,
traverseCollectionCursor as actionTraverseCollectionCursor,

View File

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import Cursor from 'netlify-cms-lib-util/Cursor'
import { Cursor } from 'netlify-cms-lib-util';
import { selectSearchedEntries } from 'Reducers';
import {
searchEntries as actionSearchEntries,

View File

@ -3,11 +3,10 @@ import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import styled from 'react-emotion';
import { Link } from 'react-router-dom';
import c from 'classnames';
import { resolvePath } from 'netlify-cms-lib-util';
import { colors, colorsRaw, components, lengths } from 'netlify-cms-ui-default';
import history from 'Routing/history';
import { resolvePath } from 'netlify-cms-lib-util/path';
import { VIEW_STYLE_LIST, VIEW_STYLE_GRID } from 'Constants/collectionViews';
import { colors, colorsRaw, components, lengths } from 'netlify-cms-ui-default/styles';
const ListCardLink = styled(Link)`
${components.card};

View File

@ -4,7 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import styled from 'react-emotion';
import Waypoint from 'react-waypoint';
import { Map } from 'immutable';
import Cursor from 'netlify-cms-lib-util/Cursor';
import { Cursor } from 'netlify-cms-lib-util';
import { selectFields, selectInferedField } from 'Reducers/collections';
import EntryCard from './EntryCard';

View File

@ -4,8 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import styled, { css } from 'react-emotion';
import { NavLink } from 'react-router-dom';
import uuid from 'uuid/v4';
import Icon from 'netlify-cms-ui-default/Icon';
import { components, colors, colorsRaw, lengths } from 'netlify-cms-ui-default/styles';
import { Icon, components, colors, colorsRaw, lengths } from 'netlify-cms-ui-default';
import { searchCollections } from 'Actions/collections';
import { getCollectionUrl } from 'Lib/urlHelper';

View File

@ -4,7 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { Map } from 'immutable';
import { get } from 'lodash';
import { connect } from 'react-redux';
import Loader from 'netlify-cms-ui-default/Loader';
import { Loader } from 'netlify-cms-ui-default';
import history from 'Routing/history';
import { logoutUser } from 'Actions/auth';
import {

View File

@ -1,7 +1,7 @@
import React from 'react';
import styled, { css, cx } from 'react-emotion';
import { partial, uniqueId } from 'lodash';
import { colors, colorsRaw, transitions, lengths, borders } from 'netlify-cms-ui-default/styles';
import { colors, colorsRaw, transitions, lengths, borders } from 'netlify-cms-ui-default';
import { resolveWidget } from 'Lib/registry';
import Widget from './Widget';

View File

@ -3,10 +3,8 @@ import React, { Component } from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import styled, { css, injectGlobal } from 'react-emotion';
import SplitPane from 'react-split-pane';
import classnames from 'classnames';
import { Icon, colors, colorsRaw, components, transitions } from 'netlify-cms-ui-default';
import { ScrollSync, ScrollSyncPane } from './EditorScrollSync';
import Icon from 'netlify-cms-ui-default/Icon';
import { colors, colorsRaw, components, transitions } from 'netlify-cms-ui-default/styles';
import EditorControlPane from './EditorControlPane/EditorControlPane';
import EditorPreviewPane from './EditorPreviewPane/EditorPreviewPane';
import EditorToolbar from './EditorToolbar';

View File

@ -4,7 +4,7 @@ import styled from 'react-emotion';
import { List, Map } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Frame from 'react-frame-component';
import { lengths } from 'netlify-cms-ui-default/styles';
import { lengths } from 'netlify-cms-ui-default';
import { resolveWidget, getPreviewTemplate, getPreviewStyles } from 'Lib/registry';
import { ErrorBoundary } from 'UI';
import { selectTemplateName, selectInferedField } from 'Reducers/collections';

View File

@ -1,8 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'react-emotion';
import Icon from 'netlify-cms-ui-default/Icon';
import { colors, colorsRaw, shadows, buttons } from 'netlify-cms-ui-default/styles';
import { Icon, colors, colorsRaw, shadows, buttons } from 'netlify-cms-ui-default';
const EditorToggleButton = styled.button`
${buttons.button};

View File

@ -3,11 +3,19 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import styled, { css } from 'react-emotion';
import { Link } from 'react-router-dom';
import {
Icon,
Dropdown,
DropdownItem,
StyledDropdownButton,
colorsRaw,
colors,
components,
buttons,
lengths,
} from 'netlify-cms-ui-default';
import { status } from 'Constants/publishModes';
import SettingsDropdown from 'UI/SettingsDropdown';
import Dropdown, { DropdownItem, StyledDropdownButton } from 'netlify-cms-ui-default/Dropdown';
import Icon from 'netlify-cms-ui-default/Icon';
import { colorsRaw, colors, components, buttons, lengths } from 'netlify-cms-ui-default/styles';
import { stripProtocol } from 'Lib/urlHelper';
const styles = {

View File

@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from "react-immutable-proptypes";
import { isBoolean } from 'lodash';
import Toggle from 'netlify-cms-ui-default/Toggle';
import { Toggle } from 'netlify-cms-ui-default';
export default class BooleanControl extends React.Component {
render() {

View File

@ -5,8 +5,7 @@ import { List, Map } from 'immutable';
import { partial } from 'lodash';
import c from 'classnames';
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
import Icon from 'netlify-cms-ui-default/Icon';
import ListItemTopBar from 'netlify-cms-ui-default/ListItemTopBar';
import { Icon, ListItemTopBar } from 'netlify-cms-ui-default';
import ObjectControl from 'EditorWidgets/Object/ObjectControl';
function ListItem(props) {

View File

@ -3,9 +3,7 @@ import React from 'react';
import { List } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import c from 'classnames';
import Dropdown, { DropdownItem, DropdownButton } from 'netlify-cms-ui-default/Dropdown';
import Toggle from 'netlify-cms-ui-default/Toggle';
import Icon from 'netlify-cms-ui-default/Icon';
import { Icon, Toggle, Dropdown, DropdownItem, DropdownButton } from 'netlify-cms-ui-default';
import ToolbarButton from './ToolbarButton';
export default class Toolbar extends React.Component {

View File

@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import c from 'classnames';
import Icon from 'netlify-cms-ui-default/Icon';
import { Icon } from 'netlify-cms-ui-default';
const ToolbarButton = ({ type, label, icon, onClick, isActive, isHidden, disabled }) => {
const active = isActive && type && isActive(type);

View File

@ -7,7 +7,7 @@ import { resolveWidget, getEditorComponents } from 'Lib/registry';
import { openMediaLibrary, removeInsertedMedia } from 'Actions/mediaLibrary';
import { addAsset } from 'Actions/media';
import { getAsset } from 'Reducers';
import ListItemTopBar from 'netlify-cms-ui-default/ListItemTopBar';
import { ListItemTopBar } from 'netlify-cms-ui-default';
import { getEditorControl } from '../index';
class Shortcode extends React.Component {

View File

@ -4,8 +4,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { Map } from 'immutable';
import { partial } from 'lodash';
import c from 'classnames';
import { Icon } from 'netlify-cms-ui-default';
import { resolveWidget } from 'Lib/registry';
import Icon from 'netlify-cms-ui-default/Icon';
const TopBar = ({ collapsed, onCollapseToggle }) => (
<div className="nc-objectControl-topBar">

View File

@ -6,7 +6,7 @@ import { List, Map } from 'immutable';
import { connect } from 'react-redux';
import { debounce } from 'lodash';
import { query, clearSearch } from 'Actions/search';
import Loader from 'netlify-cms-ui-default/Loader';
import { Loader } from 'netlify-cms-ui-default';
function escapeRegexCharacters(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'react-emotion';
import { colors } from 'netlify-cms-ui-default/styles';
import { colors } from 'netlify-cms-ui-default';
const EmptyMessageContainer= styled.div`
height: 100%;

View File

@ -2,7 +2,7 @@ import React from 'react';
import { connect } from 'react-redux';
import { orderBy, map } from 'lodash';
import fuzzy from 'fuzzy';
import { resolvePath, fileExtension } from 'netlify-cms-lib-util/path';
import { resolvePath, fileExtension } from 'netlify-cms-lib-util';
import { changeDraftField } from 'Actions/entries';
import {
loadMedia as loadMediaAction,

View File

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import styled, { css } from 'react-emotion';
import { FileUploadButton } from 'UI';
import { buttons, shadows } from 'netlify-cms-ui-default/styles';
import { buttons, shadows } from 'netlify-cms-ui-default';
const styles = {
button: css`

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'react-emotion';
import { colors, borders, lengths } from 'netlify-cms-ui-default/styles';
import { colors, borders, lengths } from 'netlify-cms-ui-default';
const Card = styled.div`
width: ${props => props.width};

View File

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import styled from 'react-emotion'
import MediaLibraryCard from './MediaLibraryCard';
import { colors } from 'netlify-cms-ui-default/styles';
import { colors } from 'netlify-cms-ui-default';
const CardGridContainer = styled.div`
overflow-y: auto;

View File

@ -1,8 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'react-emotion';
import Icon from 'netlify-cms-ui-default/Icon';
import { shadows, colors } from 'netlify-cms-ui-default/styles';
import { Icon, shadows, colors } from 'netlify-cms-ui-default';
const CloseButton = styled.button`
${shadows.dropMiddle};

View File

@ -9,7 +9,7 @@ import MediaLibraryHeader from './MediaLibraryHeader';
import MediaLibraryActions from './MediaLibraryActions';
import MediaLibraryCardGrid from './MediaLibraryCardGrid';
import EmptyMessage from './EmptyMessage';
import { buttons, shadows, colors, borders, lengths } from 'netlify-cms-ui-default/styles';
import { buttons, shadows, colors, borders, lengths } from 'netlify-cms-ui-default';
/**
* Responsive styling needs to be overhauled. Current setup requires specifying

View File

@ -1,8 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'react-emotion';
import Icon from 'netlify-cms-ui-default/Icon';
import { lengths, colors } from 'netlify-cms-ui-default/styles';
import { Icon, lengths, colors } from 'netlify-cms-ui-default';
const SearchContainer = styled.div`
height: 37px;

View File

@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import { css } from 'react-emotion';
import { colors } from 'netlify-cms-ui-default/styles';
import { colors } from 'netlify-cms-ui-default';
const DefaultErrorComponent = () => {
};

View File

@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { css, cx, injectGlobal } from 'react-emotion';
import ReactModal from 'react-modal';
import { transitions, shadows, lengths } from 'netlify-cms-ui-default/styles';
import { transitions, shadows, lengths } from 'netlify-cms-ui-default';
injectGlobal`
.ReactModal__Body--open {

View File

@ -1,8 +1,6 @@
import React from 'react';
import styled, { css } from 'react-emotion';
import Dropdown, { DropdownItem, DropdownButton } from 'netlify-cms-ui-default/Dropdown';
import Icon from 'netlify-cms-ui-default/Icon';
import { colors } from 'netlify-cms-ui-default/styles';
import { Icon, Dropdown, DropdownItem, DropdownButton, colors } from 'netlify-cms-ui-default';
import { stripProtocol } from 'Lib/urlHelper';
const styles = {

View File

@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import React from 'react';
import PropTypes from 'prop-types';
import { css, injectGlobal, cx } from 'react-emotion';
import 'redux-notifications/lib/styles.css'; // Import default redux-notifications styles into global scope.
import { shadows, colors, lengths } from 'netlify-cms-ui-default/styles';
//import 'redux-notifications/lib/styles.css'; // Import default redux-notifications styles into global scope.
import { shadows, colors, lengths } from 'netlify-cms-ui-default';
injectGlobal`
.notif__container {

View File

@ -4,9 +4,15 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import styled from 'react-emotion';
import { OrderedMap } from 'immutable';
import { connect } from 'react-redux';
import Dropdown, { DropdownItem, StyledDropdownButton } from 'netlify-cms-ui-default/Dropdown';
import Loader from 'netlify-cms-ui-default/Loader';
import { lengths, components, shadows } from 'netlify-cms-ui-default/styles';
import {
Dropdown,
DropdownItem,
StyledDropdownButton,
Loader,
lengths,
components,
shadows,
} from 'netlify-cms-ui-default';
import { createNewEntry } from 'Actions/collections';
import {
loadUnpublishedEntries,

View File

@ -1,7 +1,7 @@
import React from 'react';
import styled, { css } from 'react-emotion';
import { Link } from 'react-router-dom';
import { components, colors, colorsRaw, transitions, buttons } from 'netlify-cms-ui-default/styles';
import { components, colors, colorsRaw, transitions, buttons } from 'netlify-cms-ui-default';
const styles = {
text: css`

View File

@ -4,7 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import styled, { css, cx } from 'react-emotion';
import moment from 'moment';
import { capitalize } from 'lodash'
import { colors, colorsRaw, lengths } from 'netlify-cms-ui-default/styles';
import { colors, colorsRaw, lengths } from 'netlify-cms-ui-default';
import { status } from 'Constants/publishModes';
import { DragSource, DropTarget, HTML5DragDrop } from 'UI'
import WorkflowCard from './WorkflowCard';

View File

@ -1,5 +1,5 @@
import { fromJS, Map } from 'immutable';
import Cursor from 'netlify-cms-lib-util/Cursor'
import { Cursor } from 'netlify-cms-lib-util';
import {
ENTRIES_SUCCESS,
} from 'Actions/entries';

View File

@ -1,5 +1,5 @@
import { Map } from 'immutable';
import { resolvePath } from 'netlify-cms-lib-util/path';
import { resolvePath } from 'netlify-cms-lib-util';
import { ADD_ASSET, REMOVE_ASSET } from 'Actions/media';
import AssetProxy from 'ValueObjects/AssetProxy';

View File

@ -1,4 +1,4 @@
import { resolvePath } from 'netlify-cms-lib-util/path';
import { resolvePath } from 'netlify-cms-lib-util';
import { currentBackend } from 'Backends/backend';
import { getIntegrationProvider } from 'Integrations';
import { selectIntegration } from 'Reducers';

View File

@ -0,0 +1,27 @@
const path = require('path');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const baseConfig = require('../../webpack.config.js');
module.exports = {
...baseConfig,
context: path.join(__dirname, 'src'),
entry: './index.js',
module: {
noParse: /\.css$/,
...baseConfig.module,
},
devServer: {
contentBase: './example',
watchContentBase: true,
quiet: true,
host: 'localhost',
port: 8080,
},
plugins: [
new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: {
messages: ['Netlify CMS is now running at http://localhost:8080'],
},
}),
],
};

View File

@ -0,0 +1,3 @@
const config = require('../../babel.config.js');
module.exports = config;

View File

@ -2,6 +2,7 @@
"name": "netlify-cms-editor-component-image",
"description": "Image component for Netlify CMS editor widget",
"version": "2.0.0-alpha.0",
"main": "dist/netlify-cms-editor-component-image.js",
"license": "MIT",
"keywords": [
"netlify",
@ -9,14 +10,21 @@
"editor",
"component"
],
"sideEffects": false,
"scripts": {
"watch": "parcel watch src/*.js --out-dir . --no-cache",
"build": "parcel build src/*.js --out-dir . --no-cache"
},
"dependencies": {
"react": "^16.4.1"
"watch": "webpack -w",
"build": "cross-env NODE_ENV=production webpack"
},
"devDependencies": {
"parcel-bundler": "^1.9.4"
"@babel/cli": "^7.0.0-beta.54",
"@babel/core": "^7.0.0-beta.54",
"cross-env": "^5.2.0",
"rollup": "^0.63.2",
"rollup-plugin-babel": "^4.0.0-beta.7",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0"
},
"peerDependencies": {
"react": "^16.4.1"
}
}

View File

@ -0,0 +1 @@
module.exports = require('../../webpack.config.js');

View File

@ -0,0 +1,3 @@
const config = require('../../babel.config.js');
module.exports = config;

View File

@ -2,8 +2,8 @@
"name": "netlify-cms-lib-auth",
"description": "Shared authentication functionality for Netlify CMS.",
"version": "2.0.0-alpha.0",
"main": "dist/netlify-cms-lib-auth.js",
"license": "MIT",
"main": "src/index.js",
"files": [
"src/",
"dist/"
@ -11,18 +11,25 @@
"keywords": [
"netlify-cms"
],
"sideEffects": false,
"scripts": {
"watch": "parcel watch src/*.js --out-dir . --no-cache",
"build": "parcel build src/*.js --out-dir . --no-cache"
"watch": "webpack -w",
"build": "cross-env NODE_ENV=production webpack"
},
"dependencies": {
"immutable": "^3.7.6",
"lodash": "^4.13.1",
"uuid": "^3.1.0"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"parcel-bundler": "^1.9.4"
"@babel/cli": "^7.0.0-beta.54",
"@babel/core": "^7.0.0-beta.54",
"cross-env": "^5.2.0",
"rollup": "^0.63.2",
"rollup-plugin-babel": "^4.0.0-beta.7",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0"
},
"peerDependencies": {
"immutable": "^3.7.6",
"lodash": "^4.13.1"
}
}

View File

@ -0,0 +1,2 @@
export NetlifyAuthenticator from './netlify-auth';
export ImplicitAuthenticator from './implicit-oauth';

View File

@ -0,0 +1 @@
module.exports = require('../../webpack.config.js');

View File

@ -0,0 +1,3 @@
const config = require('../../babel.config.js');
module.exports = config;

View File

@ -2,23 +2,30 @@
"name": "netlify-cms-lib-util",
"description": "Shared utilities for Netlify CMS.",
"version": "2.0.0-alpha.0",
"main": "dist/netlify-cms-lib-util.js",
"license": "MIT",
"main": "index.js",
"keywords": [
"netlify-cms"
],
"sideEffects": false,
"scripts": {
"watch": "parcel watch src/*.js --out-dir . --no-cache",
"build": "parcel build src/*.js --out-dir . --no-cache"
"watch": "webpack -w",
"build": "cross-env NODE_ENV=production webpack"
},
"dependencies": {
"immutable": "^3.7.6",
"localforage": "^1.4.2",
"lodash": "^4.13.1"
"localforage": "^1.4.2"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"parcel-bundler": "^1.9.4"
"@babel/cli": "^7.0.0-beta.54",
"@babel/core": "^7.0.0-beta.54",
"cross-env": "^5.2.0",
"rollup": "^0.63.2",
"rollup-plugin-babel": "^4.0.0-beta.7",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0"
},
"peerDependencies": {
"immutable": "^3.7.6",
"lodash": "^4.13.1"
}
}

View File

@ -1,4 +1,4 @@
import { fileExtensionWithSeparator, fileExtension } from '../pathHelper';
import { fileExtensionWithSeparator, fileExtension } from '../path';
describe('fileExtensionWithSeparator', () => {
it('should return the extension of a file', () => {

View File

@ -0,0 +1,7 @@
export APIError from './APIError';
export Cursor, { CURSOR_COMPATIBILITY_SYMBOL } from './Cursor';
export EditorialWorkflowError from './EditorialWorkflowError';
export localForage from './localForage';
export { resolvePath, basename, fileExtensionWithSeparator, fileExtension } from './path';
export { filterPromises, resolvePromiseProperties, then } from './promise';
export unsentRequest from './unsentRequest';

View File

@ -0,0 +1 @@
module.exports = require('../../webpack.config.js');

View File

@ -0,0 +1,3 @@
const config = require('../../babel.config.js');
module.exports = config;

View File

@ -3,29 +3,33 @@
"description": "Default UI components for Netlify CMS.",
"version": "2.0.0-alpha.0",
"license": "MIT",
"main": "index.js",
"main": "dist/netlify-cms-ui-default.js",
"keywords": [
"netlify-cms"
],
"sideEffects": false,
"scripts": {
"watch": "parcel watch src/*.js --out-dir . --no-cache",
"build": "parcel build src/*.js --out-dir . --no-cache"
"watch": "webpack -w",
"build": "cross-env NODE_ENV=production webpack"
},
"dependencies": {
"classnames": "^2.2.5",
"emotion": "^9.1.3",
"lodash": "^4.13.1",
"prop-types": "^15.5.10",
"react": "^16.4.1",
"react-aria-menubutton": "^5.1.0",
"react-emotion": "^9.2.6",
"react-toggled": "^1.1.2",
"react-transition-group": "^2.2.1"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-plugin-inline-svg": "^1.0.0",
"parcel-bundler": "^1.9.4"
"@babel/cli": "^7.0.0-beta.54",
"@babel/core": "^7.0.0-beta.54",
"cross-env": "^5.2.0",
"rollup": "^0.63.2",
"rollup-plugin-babel": "^4.0.0-beta.7",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0"
},
"peerDependencies": {
"lodash": "^4.13.1",
"prop-types": "^15.5.10",
"react": "^16.4.1",
"react-emotion": "^9.2.6"
}
}

View File

@ -0,0 +1,16 @@
export Dropdown, { DropdownItem, DropdownButton, StyledDropdownButton } from './Dropdown';
export Icon from './Icon';
export ListItemTopBar from './ListItemTopBar';
export Loader from './Loader';
export Toggle from './Toggle';
export {
fonts,
colorsRaw,
colors,
lengths,
components,
buttons,
shadows,
borders,
transitions,
} from './styles';

View File

@ -1,9 +1,21 @@
import { css, injectGlobal } from 'react-emotion';
export {
fonts,
colorsRaw,
colors,
lengths,
components,
buttons,
shadows,
borders,
transitions,
};
/**
* Font Stacks
*/
export const fonts = {
const fonts = {
primary: `
-apple-system,
BlinkMacSystemFont,
@ -29,7 +41,7 @@ export const fonts = {
/**
* Theme Colors
*/
export const colorsRaw = {
const colorsRaw = {
white: '#fff',
grayLight: '#eff0f4',
gray: '#798291',
@ -48,7 +60,7 @@ export const colorsRaw = {
tealLight: '#ddf5f9',
};
export const colors = {
const colors = {
statusDraftText: colorsRaw.purple,
statusDraftBackground: colorsRaw.purpleLight,
statusReviewText: colorsRaw.Brown,
@ -78,7 +90,7 @@ export const colors = {
controlLabel: '#7a8291',
};
export const lengths = {
const lengths = {
topBarHeight: '56px',
inputPadding: '16px 20px',
borderRadius: '5px',
@ -88,15 +100,15 @@ export const lengths = {
pageMargin: '84px 18px',
};
export const borders = {
const borders = {
textField: `solid ${lengths.borderWidth} ${colors.textFieldBorder}`,
};
export const transitions = {
const transitions = {
main: '.2s ease',
};
export const shadows = {
const shadows = {
drop: css`
box-shadow: 0 2px 4px 0 rgba(19, 39, 48, .12);
`,
@ -129,7 +141,7 @@ const card = css`
background-color: #fff;
`;
export const buttons = {
const buttons = {
button: css`
border: 0;
border-radius: ${lengths.borderRadius};
@ -191,7 +203,7 @@ export const buttons = {
`,
};
export const components = {
const components = {
card,
caretDown: css`
color: ${colorsRaw.white};

View File

@ -0,0 +1 @@
module.exports = require('../../webpack.config.js');

38
webpack.config.js Normal file
View File

@ -0,0 +1,38 @@
const fs = require('fs');
const path = require('path');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const pkg = require(path.join(process.cwd(), 'package.json'));
module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
entry: './src/index.js',
output: {
path: process.cwd(),
filename: pkg.main,
library: pkg.name,
libraryTarget: 'umd',
umdNamedDefine: true,
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new FriendlyErrorsWebpackPlugin(),
],
devtool: 'source-map',
target: 'web',
externals: (context, request, cb) => {
const peerDeps = Object.keys(pkg.peerDependencies || {});
const isPeerDep = dep => new RegExp(`^${dep}/?`).test(request);
return peerDeps.some(isPeerDep) ? cb(null, request) : cb();
},
stats: {
all: false,
},
};

3428
yarn.lock

File diff suppressed because it is too large Load Diff