mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 07:03:38 +00:00
Merge pull request #214 from strapi/feature/strapi-helper-plugin
Strapi Helper Plugin
This commit is contained in:
commit
62fa4ff58d
@ -8,6 +8,14 @@
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/:plugin/main.js",
|
||||
"handler": "Admin.pluginFile",
|
||||
"config": {
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/:file",
|
||||
|
||||
@ -18,6 +18,15 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
|
||||
pluginFile: async ctx => {
|
||||
try {
|
||||
const file = fs.readFileSync(path.resolve(process.cwd(), 'plugins', ctx.params.plugin, 'admin', 'build', 'main.js'));
|
||||
ctx.body = file;
|
||||
} catch (err) {
|
||||
ctx.body = ctx.notFound();
|
||||
}
|
||||
},
|
||||
|
||||
file: async ctx => {
|
||||
try {
|
||||
const file = fs.readFileSync(path.resolve(__dirname, '..', 'public', 'build', ctx.params.file));
|
||||
|
||||
@ -14,18 +14,16 @@ class PluginHeader extends React.Component { // eslint-disable-line react/prefer
|
||||
render() {
|
||||
return (
|
||||
<div className={`${styles.pluginHeader} row`}>
|
||||
<div className="row">
|
||||
<div className="col-lg-6">
|
||||
<PluginHeaderTitle
|
||||
title={this.props.title}
|
||||
description={this.props.description}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<PluginHeaderActions
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<PluginHeaderTitle
|
||||
title={this.props.title}
|
||||
description={this.props.description}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<PluginHeaderActions
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -33,7 +33,7 @@ module.exports = {
|
||||
_.forEach(strapi.plugins, (value, pluginName) => {
|
||||
if (!_.includes(ignoredPlugins, pluginName)) {
|
||||
// Main plugin `js` file
|
||||
const pluginMainScript = $('<script>').attr('src', '/' + pluginName + '/main.js');
|
||||
const pluginMainScript = $('<script>').attr('src', `/admin/${pluginName}/main.js`);
|
||||
parsedHTML('body').append(pluginMainScript);
|
||||
}
|
||||
});
|
||||
@ -41,5 +41,4 @@ module.exports = {
|
||||
// Finally, return the HTML file with injected scripts
|
||||
return parsedHTML.html();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* PluginHeaderActions
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import styles from './styles.scss';
|
||||
|
||||
class PluginHeaderActions extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||
render() {
|
||||
const actions = this.props.actions && this.props.actions.map((action, i) => (
|
||||
<button
|
||||
key={i}
|
||||
className={`btn ${action.class} ${styles.btn}`}
|
||||
onClick={action.onClick}
|
||||
disabled={action.disabled}
|
||||
>
|
||||
{action.label}
|
||||
</button>
|
||||
));
|
||||
|
||||
return (
|
||||
<div className={styles.pluginHeaderActions}>
|
||||
<div className="pull-xs-right">
|
||||
{actions}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PluginHeaderActions.propTypes = {
|
||||
actions: React.PropTypes.array,
|
||||
};
|
||||
|
||||
export default PluginHeaderActions;
|
||||
@ -1,3 +0,0 @@
|
||||
.btn {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
// import PluginHeaderActions from '../index';
|
||||
|
||||
import expect from 'expect';
|
||||
// import { shallow } from 'enzyme';
|
||||
// import React from 'react';
|
||||
|
||||
describe('<PluginHeaderActions />', () => {
|
||||
it('Expect to have unit tests specified', () => {
|
||||
expect(true).toEqual(false);
|
||||
});
|
||||
});
|
||||
@ -23,14 +23,9 @@ const logger = require('strapi-utils').logger;
|
||||
*/
|
||||
|
||||
module.exports = (scope, cb) => {
|
||||
let defaultName = scope.name;
|
||||
if (defaultName === '.' || !defaultName) {
|
||||
defaultName = path.basename(process.cwd());
|
||||
}
|
||||
|
||||
// App info.
|
||||
_.defaults(scope, {
|
||||
name: defaultName,
|
||||
name: scope.name === '.' || !scope.name ? scope.name : path.basename(process.cwd()),
|
||||
author: process.env.USER || 'A Strapi developer',
|
||||
email: process.env.EMAIL || '',
|
||||
year: (new Date()).getFullYear(),
|
||||
|
||||
7
packages/strapi-generate-plugin/files/.editorconfig
Normal file
7
packages/strapi-generate-plugin/files/.editorconfig
Normal file
@ -0,0 +1,7 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = false
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
103
packages/strapi-generate-plugin/files/.gitattributes
vendored
Normal file
103
packages/strapi-generate-plugin/files/.gitattributes
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
# From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes
|
||||
|
||||
# Handle line endings automatically for files detected as text
|
||||
# and leave all files detected as binary untouched.
|
||||
* text=auto
|
||||
|
||||
#
|
||||
# The above will handle all files NOT found below
|
||||
#
|
||||
|
||||
#
|
||||
## These files are text and should be normalized (Convert crlf => lf)
|
||||
#
|
||||
|
||||
# source code
|
||||
*.php text
|
||||
*.css text
|
||||
*.sass text
|
||||
*.scss text
|
||||
*.less text
|
||||
*.styl text
|
||||
*.js text eol=lf
|
||||
*.coffee text
|
||||
*.json text
|
||||
*.htm text
|
||||
*.html text
|
||||
*.xml text
|
||||
*.svg text
|
||||
*.txt text
|
||||
*.ini text
|
||||
*.inc text
|
||||
*.pl text
|
||||
*.rb text
|
||||
*.py text
|
||||
*.scm text
|
||||
*.sql text
|
||||
*.sh text
|
||||
*.bat text
|
||||
|
||||
# templates
|
||||
*.ejs text
|
||||
*.hbt text
|
||||
*.jade text
|
||||
*.haml text
|
||||
*.hbs text
|
||||
*.dot text
|
||||
*.tmpl text
|
||||
*.phtml text
|
||||
|
||||
# git config
|
||||
.gitattributes text
|
||||
.gitignore text
|
||||
.gitconfig text
|
||||
|
||||
# code analysis config
|
||||
.jshintrc text
|
||||
.jscsrc text
|
||||
.jshintignore text
|
||||
.csslintrc text
|
||||
|
||||
# misc config
|
||||
*.yaml text
|
||||
*.yml text
|
||||
.editorconfig text
|
||||
|
||||
# build config
|
||||
*.npmignore text
|
||||
*.bowerrc text
|
||||
|
||||
# Heroku
|
||||
Procfile text
|
||||
.slugignore text
|
||||
|
||||
# Documentation
|
||||
*.md text
|
||||
LICENSE text
|
||||
AUTHORS text
|
||||
|
||||
|
||||
#
|
||||
## These files are binary and should be left untouched
|
||||
#
|
||||
|
||||
# (binary is a macro for -text -diff)
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.mov binary
|
||||
*.mp4 binary
|
||||
*.mp3 binary
|
||||
*.flv binary
|
||||
*.fla binary
|
||||
*.swf binary
|
||||
*.gz binary
|
||||
*.zip binary
|
||||
*.7z binary
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.woff binary
|
||||
*.pyc binary
|
||||
*.pdf binary
|
||||
1
packages/strapi-generate-plugin/files/README.md
Normal file
1
packages/strapi-generate-plugin/files/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Strapi plugin
|
||||
@ -0,0 +1,26 @@
|
||||
/**
|
||||
*
|
||||
* Button
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import styles from './styles.scss';
|
||||
|
||||
class Button extends React.Component {
|
||||
// eslint-disable-line react/prefer-stateless-function
|
||||
render() {
|
||||
return (
|
||||
<button className={`btn btn-primary ${styles.button}`} {...this.props}>
|
||||
{this.props.label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Button.propTypes = {
|
||||
label: React.PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Button;
|
||||
@ -0,0 +1,3 @@
|
||||
.button {
|
||||
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
/*
|
||||
*
|
||||
* App actions
|
||||
*
|
||||
*/
|
||||
@ -0,0 +1,5 @@
|
||||
/*
|
||||
*
|
||||
* App constants
|
||||
*
|
||||
*/
|
||||
@ -0,0 +1,48 @@
|
||||
/**
|
||||
*
|
||||
* This component is the skeleton around the actual pages, and should only
|
||||
* contain code that should be seen on all pages. (e.g. navigation bar)
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createStructuredSelector } from 'reselect';
|
||||
import { pluginId } from 'app';
|
||||
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
// Assign plugin component to children
|
||||
const content = React.Children.map(this.props.children, child =>
|
||||
React.cloneElement(child, {
|
||||
exposedComponents: this.props.exposedComponents,
|
||||
})
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={pluginId}>
|
||||
{React.Children.toArray(content)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
App.contextTypes = {
|
||||
router: React.PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
App.propTypes = {
|
||||
children: React.PropTypes.node.isRequired,
|
||||
exposedComponents: React.PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
dispatch,
|
||||
};
|
||||
}
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
// Wrap the component to inject dispatch and state into it
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
@ -0,0 +1,18 @@
|
||||
/*
|
||||
*
|
||||
* App reducer
|
||||
*
|
||||
*/
|
||||
|
||||
import { fromJS } from 'immutable';
|
||||
|
||||
const initialState = fromJS({});
|
||||
|
||||
function appReducer(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default appReducer;
|
||||
@ -0,0 +1,25 @@
|
||||
// import { createSelector } from 'reselect';
|
||||
|
||||
/**
|
||||
* Direct selector to the list state domain
|
||||
*/
|
||||
|
||||
// const selectGlobalDomain = () => state => state.get('global');
|
||||
|
||||
const selectLocationState = () => {
|
||||
let prevRoutingState;
|
||||
let prevRoutingStateJS;
|
||||
|
||||
return state => {
|
||||
const routingState = state.get('route'); // or state.route
|
||||
|
||||
if (!routingState.equals(prevRoutingState)) {
|
||||
prevRoutingState = routingState;
|
||||
prevRoutingStateJS = routingState.toJS();
|
||||
}
|
||||
|
||||
return prevRoutingStateJS;
|
||||
};
|
||||
};
|
||||
|
||||
export { selectLocationState };
|
||||
@ -0,0 +1,20 @@
|
||||
/*
|
||||
*
|
||||
* HomePage actions
|
||||
*
|
||||
*/
|
||||
|
||||
import { LOAD_DATA, LOADED_DATA } from './constants';
|
||||
|
||||
export function loadData() {
|
||||
return {
|
||||
type: LOAD_DATA,
|
||||
};
|
||||
}
|
||||
|
||||
export function loadedData(data) {
|
||||
return {
|
||||
type: LOADED_DATA,
|
||||
data,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
/*
|
||||
*
|
||||
* HomePage constants
|
||||
*
|
||||
*/
|
||||
|
||||
export const LOAD_DATA = 'HomePage/LOAD_DATA';
|
||||
export const LOADED_DATA = 'HomePage/LOADED_DATA';
|
||||
@ -0,0 +1,99 @@
|
||||
/*
|
||||
*
|
||||
* HomePage
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createStructuredSelector } from 'reselect';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { pluginId, pluginName, pluginDescription } from 'app';
|
||||
import Button from 'components/Button';
|
||||
|
||||
import styles from './styles.scss';
|
||||
import { loadData } from './actions';
|
||||
import { makeSelectLoading, makeSelectData } from './selectors';
|
||||
|
||||
export class HomePage extends React.Component {
|
||||
generateDataBlock() {
|
||||
let dataBlock;
|
||||
if (this.props.data) {
|
||||
const items = this.props.data.map((item, i) => <li key={i}>{item}</li>);
|
||||
dataBlock = (
|
||||
<div>
|
||||
<p>Data:</p>
|
||||
<ul>{items}</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return dataBlock;
|
||||
}
|
||||
|
||||
render() {
|
||||
// Generate the data block
|
||||
const dataBlock = this.generateDataBlock();
|
||||
|
||||
// Plugin header config
|
||||
const PluginHeader = this.props.exposedComponents.PluginHeader;
|
||||
const pluginHeaderTitle = pluginName;
|
||||
const pluginHeaderDescription = pluginDescription;
|
||||
|
||||
return (
|
||||
<div className={styles.homePage}>
|
||||
<PluginHeader
|
||||
title={{
|
||||
id: `${pluginId}-title`,
|
||||
defaultMessage: pluginHeaderTitle,
|
||||
}}
|
||||
description={{
|
||||
id: `${pluginId}-description`,
|
||||
defaultMessage: pluginHeaderDescription,
|
||||
}}
|
||||
/>
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<p>This is an example of a fake API call.</p>
|
||||
<p>Loading: {this.props.loading ? 'yes' : 'no'}.</p>
|
||||
{dataBlock}
|
||||
<Button
|
||||
label={this.props.loading ? 'Loading...' : 'Submit'}
|
||||
disabled={this.props.loading}
|
||||
onClick={this.props.loadData}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
HomePage.contextTypes = {
|
||||
router: React.PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
HomePage.propTypes = {
|
||||
data: React.PropTypes.oneOfType([
|
||||
React.PropTypes.bool,
|
||||
React.PropTypes.object,
|
||||
]),
|
||||
exposedComponents: React.PropTypes.object.isRequired,
|
||||
loadData: React.PropTypes.func.isRequired,
|
||||
loading: React.PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
loadData: () => dispatch(loadData()),
|
||||
dispatch,
|
||||
};
|
||||
}
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
loading: makeSelectLoading(),
|
||||
data: makeSelectData(),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(
|
||||
injectIntl(HomePage)
|
||||
);
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
*
|
||||
* HomePage reducer
|
||||
*
|
||||
*/
|
||||
|
||||
import { fromJS } from 'immutable';
|
||||
|
||||
import { LOAD_DATA, LOADED_DATA } from './constants';
|
||||
|
||||
const initialState = fromJS({
|
||||
loading: false,
|
||||
data: false,
|
||||
});
|
||||
|
||||
function homePageReducer(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case LOAD_DATA:
|
||||
return state.set('loading', true);
|
||||
case LOADED_DATA:
|
||||
return state.set('loading', false).set('data', fromJS(action.data));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default homePageReducer;
|
||||
@ -0,0 +1,32 @@
|
||||
import { takeLatest } from 'redux-saga';
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
import { put, fork, take, cancel } from 'redux-saga/effects';
|
||||
|
||||
import { loadedData } from './actions';
|
||||
import { LOAD_DATA } from './constants';
|
||||
|
||||
export function* loadData() {
|
||||
// Fake API request delay
|
||||
yield new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// Generate a random array
|
||||
const data = Array(4).fill(0).map(() => Math.floor(Math.random() * 100));
|
||||
|
||||
yield put(loadedData(data));
|
||||
}
|
||||
|
||||
// Individual exports for testing
|
||||
export function* defaultSaga() {
|
||||
const loadDataWatcher = yield fork(takeLatest, LOAD_DATA, loadData);
|
||||
|
||||
// Suspend execution until location changes
|
||||
yield take(LOCATION_CHANGE);
|
||||
yield cancel(loadDataWatcher);
|
||||
}
|
||||
|
||||
// All sagas to be loaded
|
||||
export default [defaultSaga];
|
||||
@ -0,0 +1,18 @@
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
/**
|
||||
* Direct selector to the homePage state domain
|
||||
*/
|
||||
const selectHomePageDomain = () => state => state.get('homePage');
|
||||
|
||||
/**
|
||||
* Default selector used by HomePage
|
||||
*/
|
||||
|
||||
const makeSelectLoading = () =>
|
||||
createSelector(selectHomePageDomain(), substate => substate.get('loading'));
|
||||
|
||||
const makeSelectData = () =>
|
||||
createSelector(selectHomePageDomain(), substate => substate.get('data'));
|
||||
|
||||
export { makeSelectLoading, makeSelectData };
|
||||
@ -0,0 +1,3 @@
|
||||
.homePage {
|
||||
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"/": {
|
||||
"name": "homePage",
|
||||
"container": "HomePage"
|
||||
}
|
||||
}
|
||||
72
packages/strapi-generate-plugin/json/package.json.js
Executable file
72
packages/strapi-generate-plugin/json/package.json.js
Executable file
@ -0,0 +1,72 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
// Public node modules.
|
||||
const _ = require('lodash');
|
||||
|
||||
/**
|
||||
* Expose main package JSON of the application
|
||||
* with basic info, dependencies, etc.
|
||||
*/
|
||||
|
||||
module.exports = scope => {
|
||||
const cliPkg = scope.strapiPackageJSON || {};
|
||||
|
||||
// Finally, return the JSON.
|
||||
return _.merge(scope.appPackageJSON || {}, {
|
||||
'name': `strapi-plugin-${scope.id}`,
|
||||
'version': '0.0.0',
|
||||
'description': 'This is the description of the plugin.',
|
||||
'strapi': {
|
||||
'name': scope.name,
|
||||
'icon': 'ion-document-text'
|
||||
},
|
||||
'scripts': {
|
||||
'analyze:clean': 'node_modules/strapi-helper-plugin/node_modules/rimraf/bin.js stats.json',
|
||||
'preanalyze': 'npm run analyze:clean',
|
||||
'analyze': 'node node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js',
|
||||
'postinstall': 'npm run build:dll',
|
||||
'prebuild': 'npm run build:clean && npm run test',
|
||||
'build': 'node_modules/strapi-helper-plugin/node_modules/cross-env/bin/cross-env.js NODE_ENV=production node_modules/strapi-helper-plugin/node_modules/webpack/bin/webpack.js --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress',
|
||||
'build:clean': 'node_modules/strapi-helper-plugin/node_modules/rimraf/bin.js admin/build',
|
||||
'build:dll': 'node node_modules/strapi-helper-plugin/lib/internals/scripts/dependencies.js',
|
||||
'start': 'node_modules/strapi-helper-plugin/node_modules/cross-env/bin/cross-env.js NODE_ENV=development node node_modules/strapi-helper-plugin/lib/server',
|
||||
'generate': 'node_modules/strapi-helper-plugin/node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js',
|
||||
'lint': 'node_modules/strapi-helper-plugin/node_modules/eslint/bin/eslint.js --ignore-path .gitignore --config node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin',
|
||||
'pretest': 'npm run lint',
|
||||
'prettier': 'node_modules/strapi-helper-plugin/node_modules/prettier/bin/prettier.js --single-quote --trailing-comma es5 --write \'{admin,__{tests,mocks}__}/**/*.js\'',
|
||||
'test': 'echo Tests are not implemented.',
|
||||
'prepublish': 'npm run build'
|
||||
},
|
||||
'dependencies': {},
|
||||
'devDependencies': {
|
||||
'strapi-helper-plugin': '3.0.0-alpha.3'
|
||||
},
|
||||
'author': {
|
||||
'name': scope.author || 'A Strapi developer',
|
||||
'email': scope.email || '',
|
||||
'url': scope.website || ''
|
||||
},
|
||||
'maintainers': [{
|
||||
'name': scope.author || 'A Strapi developer',
|
||||
'email': scope.email || '',
|
||||
'url': scope.website || ''
|
||||
}],
|
||||
'engines': {
|
||||
'node': '>= 7.0.0',
|
||||
'npm': '>= 3.0.0'
|
||||
},
|
||||
'license': scope.license || 'MIT'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get dependencies version
|
||||
*/
|
||||
|
||||
function getDependencyVersion(packageJSON, module) {
|
||||
return module === packageJSON.name ? packageJSON.version : packageJSON.dependencies && packageJSON.dependencies[module];
|
||||
}
|
||||
@ -6,6 +6,8 @@
|
||||
|
||||
// Public node modules.
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* This `before` function is run before generating targets.
|
||||
@ -31,19 +33,29 @@ module.exports = (scope, cb) => {
|
||||
ext: '.js'
|
||||
});
|
||||
|
||||
// Plugin info.
|
||||
_.defaults(scope, {
|
||||
name: scope.args.name || scope.id,
|
||||
author: scope.author || 'A Strapi developer',
|
||||
email: scope.email || '',
|
||||
year: (new Date()).getFullYear(),
|
||||
license: 'MIT'
|
||||
});
|
||||
|
||||
// Take another pass to take advantage of the defaults absorbed in previous passes.
|
||||
_.defaults(scope, {
|
||||
filename: `${scope.globalID}${scope.ext}`
|
||||
});
|
||||
|
||||
|
||||
// Humanize output.
|
||||
_.defaults(scope, {
|
||||
humanizeId: _.camelCase(scope.id).toLowerCase(),
|
||||
humanizeId: scope.id.toLowerCase(),
|
||||
humanizedPath: '`./plugins`'
|
||||
});
|
||||
|
||||
// Copy the admin files.
|
||||
fs.copySync(path.resolve(__dirname, '..', 'files'), path.resolve(scope.rootPath, 'plugins', scope.humanizeId));
|
||||
|
||||
// Trigger callback with no error to proceed.
|
||||
return cb.success();
|
||||
};
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
const path = require('path');
|
||||
|
||||
// Local dependencies.
|
||||
const packageJSON = require('../json/package.json.js');
|
||||
const routesJSON = require('../json/routes.json.js');
|
||||
|
||||
/**
|
||||
@ -35,6 +36,11 @@ module.exports = {
|
||||
// Generate routes.
|
||||
'plugins/:humanizeId/config/routes.json': {
|
||||
jsonfile: routesJSON
|
||||
}
|
||||
},
|
||||
|
||||
// Main package.
|
||||
'plugins/:humanizeId/package.json': {
|
||||
jsonfile: packageJSON
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
"lib": "./lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": "~0.30.0",
|
||||
"lodash": "^4.16.5",
|
||||
"pluralize": "~3.1.0"
|
||||
},
|
||||
|
||||
10
packages/strapi-helper-plugin/.gitignore
vendored
Normal file
10
packages/strapi-helper-plugin/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# Don't check auto-generated stuff into git
|
||||
coverage
|
||||
build
|
||||
node_modules
|
||||
stats.json
|
||||
|
||||
# Cruft
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
.idea
|
||||
5
packages/strapi-helper-plugin/README.md
Normal file
5
packages/strapi-helper-plugin/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Strapi Helper Plugin
|
||||
|
||||
## Description
|
||||
|
||||
Helper to develop Strapi plugins.
|
||||
@ -2,11 +2,9 @@ const resolve = require('path').resolve;
|
||||
|
||||
const pullAll = require('lodash/pullAll');
|
||||
const uniq = require('lodash/uniq');
|
||||
const merge = require('lodash/uniq');
|
||||
|
||||
const ReactBoilerplate = {
|
||||
// This refers to the react-boilerplate version this project is based on.
|
||||
version: '3.0.0',
|
||||
|
||||
const StrapiPlugin = {
|
||||
/**
|
||||
* The DLL Plugin provides a dramatic speed increase to webpack build and hot module reloading
|
||||
* by caching the module metadata for all of our npm dependencies. We enable it by default
|
||||
@ -26,9 +24,7 @@ const ReactBoilerplate = {
|
||||
'compression',
|
||||
'cross-env',
|
||||
'express',
|
||||
'ip',
|
||||
'minimist',
|
||||
'sanitize.css',
|
||||
],
|
||||
|
||||
/**
|
||||
@ -38,20 +34,20 @@ const ReactBoilerplate = {
|
||||
include: ['core-js', 'eventsource-polyfill', 'babel-polyfill', 'lodash'],
|
||||
|
||||
// The path where the DLL manifest and bundle will get built
|
||||
path: resolve('../node_modules/react-boilerplate-dlls'),
|
||||
path: resolve('../node_modules/strapi-plugin-dlls'),
|
||||
},
|
||||
|
||||
entry(pkg) {
|
||||
const dependencyNames = Object.keys(pkg.dependencies);
|
||||
const exclude = pkg.dllPlugin.exclude || ReactBoilerplate.dllPlugin.defaults.exclude;
|
||||
const include = pkg.dllPlugin.include || ReactBoilerplate.dllPlugin.defaults.include;
|
||||
entry(helperPkg, pluginPkg) {
|
||||
const dependencyNames = merge(Object.keys(helperPkg.dependencies), Object.keys(pluginPkg.dependencies));
|
||||
const exclude = pluginPkg.dllPlugin.exclude || StrapiPlugin.dllPlugin.defaults.exclude;
|
||||
const include = pluginPkg.dllPlugin.include || StrapiPlugin.dllPlugin.defaults.include;
|
||||
const includeDependencies = uniq(dependencyNames.concat(include));
|
||||
|
||||
return {
|
||||
reactBoilerplateDeps: pullAll(includeDependencies, exclude),
|
||||
strapiPluginDeps: pullAll(includeDependencies, exclude),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ReactBoilerplate;
|
||||
module.exports = StrapiPlugin;
|
||||
@ -0,0 +1,93 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"prettier"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"es6": true
|
||||
},
|
||||
"plugins": [
|
||||
"redux-saga",
|
||||
"react",
|
||||
"jsx-a11y"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"comma-dangle": [
|
||||
2,
|
||||
"always-multiline"
|
||||
],
|
||||
"import/newline-after-import": 0,
|
||||
"import/no-dynamic-require": 0,
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"import/no-named-as-default": 0,
|
||||
"import/no-unresolved": 2,
|
||||
"import/prefer-default-export": 0,
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
"builtin",
|
||||
"external",
|
||||
"internal",
|
||||
"parent",
|
||||
"sibling",
|
||||
"index"
|
||||
]
|
||||
}
|
||||
],
|
||||
"import/imports-first": 2,
|
||||
"indent": [
|
||||
2,
|
||||
2,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"jsx-a11y/aria-props": 2,
|
||||
"jsx-a11y/heading-has-content": 0,
|
||||
"jsx-a11y/href-no-hash": 2,
|
||||
"jsx-a11y/label-has-for": 2,
|
||||
"jsx-a11y/mouse-events-have-key-events": 2,
|
||||
"jsx-a11y/role-has-required-aria-props": 2,
|
||||
"jsx-a11y/role-supports-aria-props": 2,
|
||||
"max-len": 0,
|
||||
"newline-per-chained-call": 0,
|
||||
"no-console": 1,
|
||||
"no-use-before-define": 0,
|
||||
"prefer-template": 2,
|
||||
"class-methods-use-this": 0,
|
||||
"react/forbid-prop-types": 0,
|
||||
"react/jsx-first-prop-new-line": [
|
||||
2,
|
||||
"multiline"
|
||||
],
|
||||
"react/jsx-filename-extension": 0,
|
||||
"react/jsx-no-target-blank": 0,
|
||||
"react/require-extension": 0,
|
||||
"react/self-closing-comp": 0,
|
||||
"redux-saga/no-yield-in-race": 2,
|
||||
"redux-saga/yield-effects": 2,
|
||||
"require-yield": 0,
|
||||
"react/no-unescaped-entities": 0,
|
||||
"react/prefer-stateless-function": 0,
|
||||
"react/sort-prop-types": 2
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"webpack": {
|
||||
"config": "./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.test.babel.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
const config = require('./.eslintrc.json');
|
||||
|
||||
// Update the eslint configuration for `strapi-helper-plugin` module
|
||||
if (process.env.IS_HELPER) {
|
||||
config.settings['import/resolver'].webpack.config = './lib/internals/webpack/webpack.test.babel.js'
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
@ -39,12 +39,12 @@ module.exports = {
|
||||
// Generate index.js and index.test.js
|
||||
const actions = [{
|
||||
type: 'add',
|
||||
path: '../../app/components/{{properCase name}}/index.js',
|
||||
path: '../../../../../admin/src/components/{{properCase name}}/index.js',
|
||||
templateFile: data.type === 'ES6 Class' ? './component/es6.js.hbs' : './component/stateless.js.hbs',
|
||||
abortOnFail: true,
|
||||
}, {
|
||||
type: 'add',
|
||||
path: '../../app/components/{{properCase name}}/tests/index.test.js',
|
||||
path: '../../../../../admin/src/components/{{properCase name}}/tests/index.test.js',
|
||||
templateFile: './component/test.js.hbs',
|
||||
abortOnFail: true,
|
||||
}];
|
||||
@ -53,7 +53,7 @@ module.exports = {
|
||||
if (data.wantCSS) {
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/components/{{properCase name}}/styles.scss',
|
||||
path: '../../../../../admin/src/components/{{properCase name}}/styles.scss',
|
||||
templateFile: './component/styles.scss.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -63,7 +63,7 @@ module.exports = {
|
||||
if (data.wantMessages) {
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/components/{{properCase name}}/messages.js',
|
||||
path: '../../../../../admin/src/components/{{properCase name}}/messages.js',
|
||||
templateFile: './component/messages.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -0,0 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* {{ properCase name }} constants
|
||||
*
|
||||
*/
|
||||
|
||||
export const DEFAULT_ACTION = 'src/{{ properCase name }}/DEFAULT_ACTION';
|
||||
@ -48,12 +48,12 @@ module.exports = {
|
||||
// Generate index.js and index.test.js
|
||||
const actions = [{
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/index.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/index.js',
|
||||
templateFile: './container/index.js.hbs',
|
||||
abortOnFail: true,
|
||||
}, {
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/tests/index.test.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/tests/index.test.js',
|
||||
templateFile: './container/test.js.hbs',
|
||||
abortOnFail: true,
|
||||
}];
|
||||
@ -62,7 +62,7 @@ module.exports = {
|
||||
if (data.wantCSS) {
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/styles.scss',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/styles.scss',
|
||||
templateFile: './container/styles.scss.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -72,7 +72,7 @@ module.exports = {
|
||||
if (data.wantMessages) {
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/messages.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/messages.js',
|
||||
templateFile: './container/messages.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -84,13 +84,13 @@ module.exports = {
|
||||
// Actions
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/actions.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/actions.js',
|
||||
templateFile: './container/actions.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/tests/actions.test.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/tests/actions.test.js',
|
||||
templateFile: './container/actions.test.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -98,7 +98,7 @@ module.exports = {
|
||||
// Constants
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/constants.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/constants.js',
|
||||
templateFile: './container/constants.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -106,13 +106,13 @@ module.exports = {
|
||||
// Selectors
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/selectors.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/selectors.js',
|
||||
templateFile: './container/selectors.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/tests/selectors.test.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/tests/selectors.test.js',
|
||||
templateFile: './container/selectors.test.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -120,13 +120,13 @@ module.exports = {
|
||||
// Reducer
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/reducer.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/reducer.js',
|
||||
templateFile: './container/reducer.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/tests/reducer.test.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/tests/reducer.test.js',
|
||||
templateFile: './container/reducer.test.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -136,13 +136,13 @@ module.exports = {
|
||||
if (data.wantSagas) {
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/sagas.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/sagas.js',
|
||||
templateFile: './container/sagas.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/containers/{{properCase name}}/tests/sagas.test.js',
|
||||
path: '../../../../../admin/src/containers/{{properCase name}}/tests/sagas.test.js',
|
||||
templateFile: './container/sagas.test.js.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const componentGenerator = require('./component/index.js');
|
||||
const containerGenerator = require('./container/index.js');
|
||||
@ -18,10 +19,10 @@ module.exports = (plop) => {
|
||||
plop.setGenerator('language', languageGenerator);
|
||||
plop.addHelper('directory', (comp) => {
|
||||
try {
|
||||
fs.accessSync(`app/containers/${comp}`, fs.F_OK);
|
||||
return `containers/${comp}`;
|
||||
fs.accessSync(`${path.resolve(process.cwd(), 'admin', 'src', 'containers', comp)}`, fs.F_OK);
|
||||
return `${path.resolve(process.cwd(), 'admin', 'src', 'containers', comp)}`;
|
||||
} catch (e) {
|
||||
return `components/${comp}`;
|
||||
return `${path.resolve(process.cwd(), 'admin', 'src', 'components', comp)}`;
|
||||
}
|
||||
});
|
||||
plop.addHelper('curly', (object, open) => (open ? '{' : '}'));
|
||||
@ -23,43 +23,43 @@ module.exports = {
|
||||
const actions = [];
|
||||
actions.push({
|
||||
type: 'modify',
|
||||
path: '../../app/i18n.js',
|
||||
path: '../../../../../admin/src/i18n.js',
|
||||
pattern: /('react-intl\/locale-data\/[a-z]+';\n)(?!.*'react-intl\/locale-data\/[a-z]+';)/g,
|
||||
templateFile: './language/intl-locale-data.hbs',
|
||||
});
|
||||
actions.push({
|
||||
type: 'modify',
|
||||
path: '../../app/i18n.js',
|
||||
path: '../../../../../admin/src/i18n.js',
|
||||
pattern: /([\n\s'[a-z]+',)(?!.*[\n\s'[a-z]+',)/g,
|
||||
templateFile: './language/app-locale.hbs',
|
||||
templateFile: './language/src-locale.hbs',
|
||||
});
|
||||
actions.push({
|
||||
type: 'modify',
|
||||
path: '../../app/i18n.js',
|
||||
path: '../../../../../admin/src/i18n.js',
|
||||
pattern: /(from\s'.\/translations\/[a-z]+.json';\n)(?!.*from\s'.\/translations\/[a-z]+.json';)/g,
|
||||
templateFile: './language/translation-messages.hbs',
|
||||
});
|
||||
actions.push({
|
||||
type: 'modify',
|
||||
path: '../../app/i18n.js',
|
||||
path: '../../../../../admin/src/i18n.js',
|
||||
pattern: /(addLocaleData\([a-z]+LocaleData\);\n)(?!.*addLocaleData\([a-z]+LocaleData\);)/g,
|
||||
templateFile: './language/add-locale-data.hbs',
|
||||
});
|
||||
actions.push({
|
||||
type: 'modify',
|
||||
path: '../../app/i18n.js',
|
||||
path: '../../../../../admin/src/i18n.js',
|
||||
pattern: /([a-z]+:\sformatTranslationMessages\([a-z]+TranslationMessages\),\n)(?!.*[a-z]+:\sformatTranslationMessages\([a-z]+TranslationMessages\),)/g,
|
||||
templateFile: './language/format-translation-messages.hbs',
|
||||
});
|
||||
actions.push({
|
||||
type: 'add',
|
||||
path: '../../app/translations/{{language}}.json',
|
||||
path: '../../../../../admin/src/translations/{{language}}.json',
|
||||
templateFile: './language/translations-json.hbs',
|
||||
abortOnFail: true,
|
||||
});
|
||||
actions.push({
|
||||
type: 'modify',
|
||||
path: '../../app/app.js',
|
||||
path: '../../../../../admin/src/app.js',
|
||||
pattern: /(System\.import\('intl\/locale-data\/jsonp\/[a-z]+\.js'\),\n)(?!.*System\.import\('intl\/locale-data\/jsonp\/[a-z]+\.js'\),)/g,
|
||||
templateFile: './language/polyfill-intl-locale.hbs',
|
||||
});
|
||||
@ -7,7 +7,7 @@ const componentExists = require('../utils/componentExists');
|
||||
|
||||
function reducerExists(comp) {
|
||||
try {
|
||||
fs.accessSync(`app/containers/${comp}/reducer.js`, fs.F_OK);
|
||||
fs.accessSync(`src/containers/${comp}/reducer.js`, fs.F_OK);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@ -16,7 +16,7 @@ function reducerExists(comp) {
|
||||
|
||||
function sagasExists(comp) {
|
||||
try {
|
||||
fs.accessSync(`app/containers/${comp}/sagas.js`, fs.F_OK);
|
||||
fs.accessSync(`src/containers/${comp}/sagas.js`, fs.F_OK);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@ -63,14 +63,14 @@ module.exports = {
|
||||
data.useSagas = sagasExists(data.component); // eslint-disable-line no-param-reassign
|
||||
actions.push({
|
||||
type: 'modify',
|
||||
path: '../../app/routes.js',
|
||||
path: '../../../../../admin/src/routes.js',
|
||||
pattern: /(\s{\n\s{0,}path: '\*',)/g,
|
||||
template: trimTemplateFile('routeWithReducer.hbs'),
|
||||
});
|
||||
} else {
|
||||
actions.push({
|
||||
type: 'modify',
|
||||
path: '../../app/routes.js',
|
||||
path: '../../../../../admin/src/routes.js',
|
||||
pattern: /(\s{\n\s{0,}path: '\*',)/g,
|
||||
template: trimTemplateFile('route.hbs'),
|
||||
});
|
||||
@ -5,8 +5,10 @@
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const pageComponents = fs.readdirSync('app/components');
|
||||
const pageContainers = fs.readdirSync('app/containers');
|
||||
const path = require('path');
|
||||
|
||||
const pageComponents = fs.readdirSync(path.resolve(process.cwd(), 'admin', 'src', 'components'));
|
||||
const pageContainers = fs.readdirSync(path.resolve(process.cwd(), 'admin', 'src', 'containers'));
|
||||
const components = pageComponents.concat(pageContainers);
|
||||
|
||||
function componentExists(comp) {
|
||||
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const path = require('path');
|
||||
|
||||
const chalk = require('chalk');
|
||||
const shelljs = require('shelljs');
|
||||
|
||||
const animateProgress = require('./helpers/progress');
|
||||
const addCheckMark = require('./helpers/checkmark');
|
||||
|
||||
const progress = animateProgress('Generating stats');
|
||||
|
||||
// Generate stats.json file with webpack
|
||||
shelljs.exec(
|
||||
`./node_modules/strapi-helper-plugin/node_modules/webpack/bin/webpack.js --config ${path.resolve(__dirname, '..', 'webpack', 'webpack.prod.babel.js')} --profile --json > stats.json`,
|
||||
addCheckMark.bind(null, callback) // Output a checkmark on completion
|
||||
);
|
||||
|
||||
// Called after webpack has finished generating the stats.json file
|
||||
function callback() {
|
||||
clearInterval(progress);
|
||||
process.stdout.write(
|
||||
`
|
||||
\n\nOpen ${chalk.magenta('http://webpack.github.io/analyse/')} in your browser and upload the stats.json file!
|
||||
${chalk.blue('\n(Tip: (\'CMD + double-click\') the link!)\n\n')}
|
||||
`
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
/*eslint-disable*/
|
||||
|
||||
// No need to build the DLL in production
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
require('shelljs/global');
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const exists = fs.existsSync;
|
||||
const writeFile = fs.writeFileSync;
|
||||
|
||||
const defaults = require('lodash/defaultsDeep');
|
||||
const pkg = require(path.join(process.cwd(), 'package.json'));
|
||||
const config = require('../config');
|
||||
const dllConfig = defaults(pkg.dllPlugin, config.dllPlugin.defaults);
|
||||
const outputPath = path.join(process.cwd(), dllConfig.path);
|
||||
const dllManifestPath = path.join(outputPath, 'package.json');
|
||||
|
||||
/**
|
||||
* I use node_modules/strapi-plugin-dlls by default just because
|
||||
* it isn't going to be version controlled and babel wont try to parse it.
|
||||
*/
|
||||
mkdir('-p', outputPath);
|
||||
|
||||
echo('Building the Webpack DLL...');
|
||||
|
||||
/**
|
||||
* Create a manifest so npm install doesnt warn us
|
||||
*/
|
||||
if (!exists(dllManifestPath)) {
|
||||
writeFile(
|
||||
dllManifestPath,
|
||||
JSON.stringify(defaults({
|
||||
name: 'strapi-plugin-dlls',
|
||||
private: true,
|
||||
author: pkg.author,
|
||||
repository: pkg.repository,
|
||||
version: pkg.version
|
||||
}), null, 2),
|
||||
|
||||
'utf8'
|
||||
)
|
||||
}
|
||||
|
||||
// the BUILDING_DLL env var is set to avoid confusing the development environment
|
||||
exec('./node_modules/strapi-helper-plugin/node_modules/cross-env/bin/cross-env.js BUILDING_DLL=true ./node_modules/strapi-helper-plugin/node_modules/webpack/bin/webpack.js --display-chunks --color --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.dll.babel.js');
|
||||
@ -1,4 +1,4 @@
|
||||
var chalk = require('chalk');
|
||||
const chalk = require('chalk');
|
||||
|
||||
/**
|
||||
* Adds mark check symbol
|
||||
@ -0,0 +1,19 @@
|
||||
const readline = require('readline');
|
||||
|
||||
/**
|
||||
* Adds an animated progress indicator
|
||||
*
|
||||
* @param {string} message The message to write next to the indicator
|
||||
*/
|
||||
const animateProgress = (message) => {
|
||||
const amountOfDots = 3;
|
||||
let i = 0;
|
||||
return setInterval(() => {
|
||||
readline.cursorTo(process.stdout, 0);
|
||||
i = (i + 1) % (amountOfDots + 1);
|
||||
const dots = new Array(i + 1).join('.');
|
||||
process.stdout.write(message + dots);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
module.exports = animateProgress;
|
||||
@ -3,7 +3,7 @@ var exec = require('child_process').exec;
|
||||
exec('npm -v', function (err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
if (parseFloat(stdout) < 3) {
|
||||
throw new Error('[ERROR: React Boilerplate] You need npm version @>=3');
|
||||
throw new Error('[ERROR: Strapi plugin] You need npm version @>=3');
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
@ -9,20 +9,57 @@ const webpack = require('webpack');
|
||||
module.exports = (options) => ({
|
||||
entry: options.entry,
|
||||
output: Object.assign({ // Compile into js/build.js
|
||||
path: path.resolve(process.cwd(), 'build'),
|
||||
path: path.resolve(process.cwd(), 'admin', 'build'),
|
||||
publicPath: '/',
|
||||
}, options.output), // Merge with env dependent settings
|
||||
module: {
|
||||
loaders: [{
|
||||
test: /\.js$/, // Transform all .js files required somewhere with Babel
|
||||
loader: 'babel',
|
||||
exclude: /node_modules/,
|
||||
query: options.babelQuery,
|
||||
use: {
|
||||
loader: 'babel',
|
||||
options: {
|
||||
"presets": [
|
||||
[
|
||||
require.resolve('babel-preset-latest'),
|
||||
{
|
||||
"es2015": {
|
||||
"modules": false,
|
||||
},
|
||||
},
|
||||
],
|
||||
require.resolve('babel-preset-react'),
|
||||
require.resolve('babel-preset-stage-0'),
|
||||
],
|
||||
"env": {
|
||||
"production": {
|
||||
"only": [
|
||||
"src",
|
||||
],
|
||||
"plugins": [
|
||||
require.resolve('babel-plugin-transform-react-remove-prop-types'),
|
||||
require.resolve('babel-plugin-transform-react-constant-elements'),
|
||||
require.resolve('babel-plugin-transform-react-inline-elements'),
|
||||
],
|
||||
},
|
||||
"test": {
|
||||
"plugins": [
|
||||
"istanbul",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
include: [
|
||||
path.join(process.cwd(), 'admin', 'src'),
|
||||
// Add the `strapi-helper-plugin` folders watched by babel
|
||||
path.join(process.cwd(), 'node_modules', 'strapi-helper-plugin', 'lib', 'src'),
|
||||
],
|
||||
}, {
|
||||
// Transform our own .css files with PostCSS and CSS-modules
|
||||
// Transform our own .scss files
|
||||
test: /\.scss$/,
|
||||
exclude: /node_modules/,
|
||||
loader: options.cssLoaders,
|
||||
// loader: 'null-loader'
|
||||
use: options.cssLoaders,
|
||||
}, {
|
||||
// Do not transform vendor's CSS with CSS-modules
|
||||
// The point is that they remain in global scope.
|
||||
@ -66,7 +103,13 @@ module.exports = (options) => ({
|
||||
new webpack.NamedModulesPlugin(),
|
||||
]),
|
||||
resolve: {
|
||||
modules: ['node_modules'],
|
||||
modules: [
|
||||
'admin/src',
|
||||
'node_modules/strapi-helper-plugin/lib/src',
|
||||
'node_modules/strapi-helper-plugin/node_modules',
|
||||
'node_modules',
|
||||
],
|
||||
symlinks: false,
|
||||
extensions: [
|
||||
'.js',
|
||||
'.jsx',
|
||||
@ -78,6 +121,13 @@ module.exports = (options) => ({
|
||||
'main',
|
||||
],
|
||||
},
|
||||
|
||||
resolveLoader: {
|
||||
modules: [
|
||||
path.join(__dirname, '..', '..', '..', 'node_modules'),
|
||||
path.join(process.cwd(), 'node_modules'),
|
||||
],
|
||||
},
|
||||
devtool: options.devtool,
|
||||
target: 'web', // Make web variables accessible to webpack, e.g. window
|
||||
});
|
||||
@ -2,8 +2,8 @@
|
||||
* DEVELOPMENT WEBPACK CONFIGURATION
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const webpack = require('webpack');
|
||||
const argv = require('minimist')(process.argv.slice(2));
|
||||
@ -28,7 +28,7 @@ module.exports = require('./webpack.base.babel')({
|
||||
entry: [
|
||||
'eventsource-polyfill', // Necessary for hot reloading with IE
|
||||
`webpack-hot-middleware/client?path=http://localhost:${port}/__webpack_hmr`,
|
||||
path.join(process.cwd(), 'app/app.js'), // Start with js/app.js
|
||||
path.join(process.cwd(), 'node_modules', 'strapi-helper-plugin', 'lib', 'src', 'app.js'),
|
||||
],
|
||||
|
||||
// Don't use hashes in dev mode for better performance
|
||||
@ -41,9 +41,25 @@ module.exports = require('./webpack.base.babel')({
|
||||
// Add development plugins
|
||||
plugins: dependencyHandlers().concat(plugins), // eslint-disable-line no-use-before-define
|
||||
|
||||
// Load the SCSS in a style tag in development
|
||||
// cssLoaders: 'style-loader!css-loader?modules&importLoaders=1&sourceMap!postcss-loader!sass-loader',
|
||||
cssLoaders: `style-loader!css-loader?localIdentName=${pluginId}[local]__[path][name]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader!sass-loader`,
|
||||
// Transform our own .scss files
|
||||
cssLoaders: [{
|
||||
loader: 'style-loader',
|
||||
}, {
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
localIdentName: `${pluginId}[local]__[path][name]__[hash:base64:5]`,
|
||||
modules: true,
|
||||
importLoaders: 1,
|
||||
sourceMap: true,
|
||||
},
|
||||
}, {
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
config: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
|
||||
},
|
||||
}, {
|
||||
loader: 'sass-loader',
|
||||
}],
|
||||
|
||||
// Process the CSS with PostCSS
|
||||
postcssPlugins: [
|
||||
@ -91,16 +107,14 @@ function dependencyHandlers() {
|
||||
];
|
||||
}
|
||||
|
||||
const dllPath = path.resolve(process.cwd(), dllPlugin.path || 'node_modules/react-boilerplate-dlls');
|
||||
const dllPath = path.resolve(process.cwd(), dllPlugin.path || 'node_modules/strapi-plugin-dlls');
|
||||
|
||||
/**
|
||||
* If DLLs aren't explicitly defined, we assume all production dependencies listed in package.json
|
||||
* Reminder: You need to exclude any server side dependencies by listing them in dllConfig.exclude
|
||||
*
|
||||
* @see https://github.com/mxstbr/react-boilerplate/tree/master/docs/general/webpack.md
|
||||
*/
|
||||
if (!dllPlugin.dlls) {
|
||||
const manifestPath = path.resolve(dllPath, 'reactBoilerplateDeps.json');
|
||||
const manifestPath = path.resolve(dllPath, 'strapiPluginDeps.json');
|
||||
|
||||
if (!fs.existsSync(manifestPath)) {
|
||||
logger.error('The DLL manifest is missing. Please run `npm run build:dll`');
|
||||
@ -14,15 +14,16 @@ const defaults = require('lodash/defaultsDeep');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const dllPlugin = require('../config').dllPlugin;
|
||||
const helperPkg = require(join(__dirname, '..', '..', '..', 'package.json'));
|
||||
|
||||
const pkg = require(join(process.cwd(), 'package.json'));
|
||||
if (!pkg.dllPlugin) { process.exit(0); }
|
||||
const dllConfig = defaults(pkg.dllPlugin, dllPlugin.defaults);
|
||||
const pluginPkg = require(join(process.cwd(), 'package.json'));
|
||||
if (!pluginPkg.dllPlugin) { pluginPkg.dllPlugin = {}; }
|
||||
const dllConfig = defaults(pluginPkg.dllPlugin, dllPlugin.defaults);
|
||||
const outputPath = join(process.cwd(), dllConfig.path);
|
||||
|
||||
module.exports = {
|
||||
context: process.cwd(),
|
||||
entry: dllConfig.dlls ? dllConfig.dlls : dllPlugin.entry(pkg),
|
||||
entry: dllPlugin.entry(helperPkg, pluginPkg),
|
||||
devtool: 'eval',
|
||||
output: {
|
||||
filename: '[name].dll.js',
|
||||
@ -32,4 +33,10 @@ module.exports = {
|
||||
plugins: [
|
||||
new webpack.DllPlugin({ name: '[name]', path: join(outputPath, '[name].json') }), // eslint-disable-line no-new
|
||||
],
|
||||
resolve: {
|
||||
modules: [
|
||||
'node_modules',
|
||||
'node_modules/strapi-helper-plugin/node_modules',
|
||||
],
|
||||
},
|
||||
};
|
||||
@ -12,20 +12,35 @@ const pluginId = pkg.name.replace(/^strapi-/i, '');
|
||||
module.exports = require('./webpack.base.babel')({
|
||||
// In production, we skip all hot-reloading stuff
|
||||
entry: [
|
||||
path.join(process.cwd(), 'app/app.js'),
|
||||
path.join(process.cwd(), 'node_modules', 'strapi-helper-plugin', 'lib', 'src', 'app.js'),
|
||||
],
|
||||
|
||||
// Utilize long-term caching by adding content hashes (not compilation hashes) to compiled assets
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
chunkFilename: '[name].[chunkhash].chunk.js',
|
||||
// publicPath: 'http://localhost:1337/settings-manager/',
|
||||
publicPath: '/content-manager/',
|
||||
publicPath: `/${pluginId}/`,
|
||||
},
|
||||
|
||||
// We use ExtractTextPlugin so we get a seperate SCSS file instead
|
||||
// of the CSS being in the JS and injected as a style tag
|
||||
cssLoaders: `style-loader!css-loader?localIdentName=${pluginId}[local]__[path][name]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader!sass-loader`,
|
||||
// Transform our own .scss files
|
||||
cssLoaders: [{
|
||||
loader: 'style-loader',
|
||||
}, {
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
localIdentName: `${pluginId}[local]__[path][name]__[hash:base64:5]`,
|
||||
modules: true,
|
||||
importLoaders: 1,
|
||||
sourceMap: true,
|
||||
},
|
||||
}, {
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
config: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
|
||||
},
|
||||
}, {
|
||||
loader: 'sass-loader',
|
||||
}],
|
||||
|
||||
// In production, we minify our CSS with cssnano
|
||||
postcssPlugins: [
|
||||
@ -45,10 +60,6 @@ module.exports = require('./webpack.base.babel')({
|
||||
async: true,
|
||||
}),
|
||||
|
||||
// Merge all duplicate modules
|
||||
new webpack.optimize.DedupePlugin(),
|
||||
|
||||
|
||||
// Minify and optimize the JavaScript
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
@ -7,7 +7,10 @@ const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const modules = [
|
||||
'src',
|
||||
'node_modules',
|
||||
'node_modules/strapi-helper-plugin/lib/src',
|
||||
'node_modules/strapi-helper-plugin/node_modules',
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
@ -27,7 +30,7 @@ module.exports = {
|
||||
preLoaders: [
|
||||
{ test: /\.js$/,
|
||||
loader: 'isparta',
|
||||
include: path.resolve('app/'),
|
||||
include: path.resolve('src/'),
|
||||
},
|
||||
],
|
||||
loaders: [
|
||||
@ -45,6 +45,8 @@ const addDevMiddlewares = (app, webpackConfig) => {
|
||||
*/
|
||||
module.exports = (app) => {
|
||||
const webpackConfig = require('../../internals/webpack/webpack.dev.babel');
|
||||
|
||||
// const webpackConfig = require(path.resolve(process.cwd(), 'node_modules', 'strapi-helper-plugin', 'internals', 'webpack', 'webpack.dev.babel'));
|
||||
addDevMiddlewares(app, webpackConfig);
|
||||
|
||||
return app;
|
||||
@ -8,18 +8,20 @@
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { syncHistoryWithStore } from 'react-router-redux';
|
||||
|
||||
import App from './containers/App';
|
||||
import createRoutes from './routes';
|
||||
import configureStore from './store';
|
||||
import { selectLocationState } from './containers/App/selectors';
|
||||
import { translationMessages } from './i18n';
|
||||
import App from 'containers/App'; // eslint-disable-line
|
||||
import { selectLocationState } from 'containers/App/selectors'; // eslint-disable-line
|
||||
import configureStore from 'store';
|
||||
import createRoutes from 'routes';
|
||||
// import { translationMessages } from 'i18n';
|
||||
|
||||
// Plugin identifier based on the package.json `name` value
|
||||
const pluginId = require('../package.json').name.replace(
|
||||
const pluginPkg = require('../../../../package.json');
|
||||
const pluginId = pluginPkg.name.replace(
|
||||
/^strapi-plugin-/i,
|
||||
''
|
||||
);
|
||||
const pluginName = pluginPkg.strapi.name;
|
||||
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
|
||||
const apiUrl = window.Strapi && `${window.Strapi.apiUrl}/${pluginId}`;
|
||||
const router = window.Strapi.router;
|
||||
|
||||
@ -51,17 +53,16 @@ Comp.contextTypes = {
|
||||
};
|
||||
|
||||
// Register the plugin
|
||||
if (window.Strapi) {
|
||||
window.Strapi.registerPlugin({
|
||||
name: 'Content Manager',
|
||||
icon: 'ion-document-text',
|
||||
id: pluginId,
|
||||
leftMenuLinks: [],
|
||||
mainComponent: Comp,
|
||||
routes: createRoutes(store),
|
||||
translationMessages,
|
||||
});
|
||||
}
|
||||
window.Strapi.registerPlugin({
|
||||
name: pluginPkg.strapi.name,
|
||||
icon: pluginPkg.strapi.icon,
|
||||
id: pluginId,
|
||||
leftMenuLinks: [],
|
||||
mainComponent: Comp,
|
||||
routes: createRoutes(store),
|
||||
// translationMessages,
|
||||
});
|
||||
|
||||
|
||||
// Export store
|
||||
export { store, apiUrl, pluginId, router };
|
||||
export { store, apiUrl, pluginId, pluginName, pluginDescription, router };
|
||||
24
packages/strapi-helper-plugin/lib/src/i18n.js
Normal file
24
packages/strapi-helper-plugin/lib/src/i18n.js
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* i18n.js
|
||||
*
|
||||
* This will setup the i18n language files and locale data for your plugin.
|
||||
*
|
||||
*/
|
||||
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
import enTranslationMessages from './translations/en.json'; // eslint-disable-line
|
||||
import frTranslationMessages from './translations/fr.json'; // eslint-disable-line
|
||||
|
||||
const translationMessages = {
|
||||
en: enTranslationMessages,
|
||||
fr: frTranslationMessages,
|
||||
};
|
||||
|
||||
const define = messages => {
|
||||
defineMessages(messages);
|
||||
};
|
||||
|
||||
|
||||
|
||||
export { translationMessages, define };
|
||||
@ -7,7 +7,7 @@ import { combineReducers } from 'redux-immutable';
|
||||
import { fromJS } from 'immutable';
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
|
||||
import globalReducer from './containers/App/reducer';
|
||||
import globalReducer from 'containers/App/reducer'; // eslint-disable-line
|
||||
|
||||
/*
|
||||
* routeReducer
|
||||
41
packages/strapi-helper-plugin/lib/src/routes.js
Normal file
41
packages/strapi-helper-plugin/lib/src/routes.js
Normal file
@ -0,0 +1,41 @@
|
||||
// These are the pages you can go to.
|
||||
// They are all wrapped in the App component, which should contain the navbar etc
|
||||
// See http://blog.mxstbr.com/2016/01/react-apps-with-pages for more information
|
||||
// about the code splitting business
|
||||
import { map } from 'lodash';
|
||||
import { getAsyncInjectors } from 'utils/asyncInjectors';
|
||||
import routes from 'routes.json'; // eslint-disable-line
|
||||
|
||||
// Try to require a node module without throwing an error
|
||||
const tryRequire = (path) => {
|
||||
try {
|
||||
return require(`containers/${path}.js`); // eslint-disable-line global-require
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default function createRoutes(store) {
|
||||
// Create reusable async injectors using getAsyncInjectors factory
|
||||
const { injectReducer, injectSagas } = getAsyncInjectors(store); // eslint-disable-line no-unused-vars
|
||||
|
||||
// Inject app sagas
|
||||
const appSagas = tryRequire('App/sagas');
|
||||
if (appSagas) injectSagas(appSagas.default);
|
||||
|
||||
return map(routes, (route, key) => ({
|
||||
path: key === '/' ? '' : key,
|
||||
name: route.name,
|
||||
getComponent(nextState, cb) {
|
||||
const reducer = tryRequire(`${route.container}/reducer`); // eslint-disable-line global-require
|
||||
const sagas = tryRequire(`${route.container}/sagas`); // eslint-disable-line global-require
|
||||
const component = tryRequire(`${route.container}/index`); // eslint-disable-line global-require
|
||||
|
||||
process.nextTick(() => {
|
||||
if (reducer) injectReducer(route.name, reducer.default);
|
||||
if (sagas) injectSagas(sagas.default);
|
||||
cb(null, component.default);
|
||||
});
|
||||
},
|
||||
}));
|
||||
}
|
||||
@ -1,8 +1,7 @@
|
||||
import { conformsTo, isEmpty, isFunction, isObject, isString } from 'lodash';
|
||||
import invariant from 'invariant';
|
||||
import warning from 'warning';
|
||||
|
||||
import createReducer from '../reducers';
|
||||
import createReducer from 'reducers';
|
||||
|
||||
/**
|
||||
* Validate the shape of redux store
|
||||
@ -18,7 +17,7 @@ export function checkStore(store) {
|
||||
};
|
||||
invariant(
|
||||
conformsTo(store, shape),
|
||||
'(app/utils...) asyncInjectors: Expected a valid redux store'
|
||||
'(src/utils...) asyncInjectors: Expected a valid redux store'
|
||||
);
|
||||
}
|
||||
|
||||
@ -31,7 +30,7 @@ export function injectAsyncReducer(store, isValid) {
|
||||
|
||||
invariant(
|
||||
isString(name) && !isEmpty(name) && isFunction(asyncReducer),
|
||||
'(app/utils...) injectAsyncReducer: Expected `asyncReducer` to be a reducer function'
|
||||
'(src/utils...) injectAsyncReducer: Expected `asyncReducer` to be a reducer function'
|
||||
);
|
||||
|
||||
store.asyncReducers[name] = asyncReducer; // eslint-disable-line no-param-reassign
|
||||
@ -48,12 +47,12 @@ export function injectAsyncSagas(store, isValid) {
|
||||
|
||||
invariant(
|
||||
Array.isArray(sagas),
|
||||
'(app/utils...) injectAsyncSagas: Expected `sagas` to be an array of generator functions'
|
||||
'(src/utils...) injectAsyncSagas: Expected `sagas` to be an array of generator functions'
|
||||
);
|
||||
|
||||
warning(
|
||||
!isEmpty(sagas),
|
||||
'(app/utils...) injectAsyncSagas: Received an empty `sagas` array'
|
||||
'(src/utils...) injectAsyncSagas: Received an empty `sagas` array'
|
||||
);
|
||||
|
||||
sagas.map(store.runSaga);
|
||||
124
packages/strapi-helper-plugin/package.json
Normal file
124
packages/strapi-helper-plugin/package.json
Normal file
@ -0,0 +1,124 @@
|
||||
{
|
||||
"name": "strapi-helper-plugin",
|
||||
"version": "3.0.0-alpha.3",
|
||||
"description": "Helper for Strapi plugins development",
|
||||
"engines": {
|
||||
"node": ">= 7.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"author": {
|
||||
"email": "hi@strapi.io",
|
||||
"name": "Strapi team",
|
||||
"url": "http://strapi.io"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Strapi team",
|
||||
"email": "hi@strapi.io",
|
||||
"url": "http://strapi.io"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "./node_modules/cross-env/bin/cross-env.js IS_HELPER=true ./node_modules/eslint/bin/eslint.js --ignore-path .gitignore --config ./lib/internals/eslint/eslint-config.js .",
|
||||
"pretest": "npm run lint",
|
||||
"prettier": "./node_modules/prettier/bin/prettier.js --single-quote --trailing-comma es5 --write \"{lib,__{tests,mocks}__}/**/*.js\"",
|
||||
"test": "echo Tests are not implemented."
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint:admin"
|
||||
],
|
||||
"dependencies": {
|
||||
"babel-polyfill": "6.13.0",
|
||||
"chalk": "1.1.3",
|
||||
"compression": "1.6.2",
|
||||
"cross-env": "3.1.3",
|
||||
"express": "4.14.0",
|
||||
"fontfaceobserver": "2.0.1",
|
||||
"history": "3.0.0",
|
||||
"immutable": "3.8.1",
|
||||
"intl": "1.2.4",
|
||||
"invariant": "2.2.1",
|
||||
"lodash": "4.15.0",
|
||||
"react": "15.3.0",
|
||||
"react-dom": "15.3.0",
|
||||
"react-helmet": "3.1.0",
|
||||
"react-intl": "2.1.3",
|
||||
"react-redux": "4.4.5",
|
||||
"react-router": "2.6.1",
|
||||
"react-router-redux": "4.0.5",
|
||||
"react-router-scroll": "0.2.1",
|
||||
"redux": "3.5.2",
|
||||
"redux-immutable": "3.0.7",
|
||||
"redux-saga": "0.11.0",
|
||||
"reselect": "2.5.3",
|
||||
"warning": "3.0.0",
|
||||
"whatwg-fetch": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.18.0",
|
||||
"babel-core": "6.18.0",
|
||||
"babel-eslint": "7.1.0",
|
||||
"babel-loader": "6.2.7",
|
||||
"babel-plugin-istanbul": "2.0.3",
|
||||
"babel-plugin-react-intl": "2.2.0",
|
||||
"babel-plugin-react-transform": "2.0.2",
|
||||
"babel-plugin-transform-async-to-generator": "^6.22.0",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.22.0",
|
||||
"babel-plugin-transform-react-constant-elements": "6.9.1",
|
||||
"babel-plugin-transform-react-inline-elements": "6.8.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "0.2.10",
|
||||
"babel-plugin-transform-runtime": "^6.15.0",
|
||||
"babel-preset-es2017": "^6.22.0",
|
||||
"babel-preset-latest": "6.16.0",
|
||||
"babel-preset-react": "6.16.0",
|
||||
"babel-preset-react-hmre": "1.1.1",
|
||||
"babel-preset-stage-0": "6.16.0",
|
||||
"chai": "3.5.0",
|
||||
"chai-enzyme": "0.5.2",
|
||||
"cheerio": "0.22.0",
|
||||
"coveralls": "2.11.14",
|
||||
"css-loader": "0.25.0",
|
||||
"enzyme": "2.5.1",
|
||||
"eslint": "3.9.0",
|
||||
"eslint-config-airbnb": "12.0.0",
|
||||
"eslint-config-airbnb-base": "9.0.0",
|
||||
"eslint-config-prettier": "^2.0.0",
|
||||
"eslint-import-resolver-webpack": "0.6.0",
|
||||
"eslint-plugin-import": "2.0.1",
|
||||
"eslint-plugin-jsx-a11y": "2.2.3",
|
||||
"eslint-plugin-react": "6.4.1",
|
||||
"eslint-plugin-redux-saga": "0.1.5",
|
||||
"eventsource-polyfill": "0.9.6",
|
||||
"expect": "1.20.2",
|
||||
"expect-jsx": "2.6.0",
|
||||
"exports-loader": "0.6.3",
|
||||
"file-loader": "0.9.0",
|
||||
"image-webpack-loader": "2.0.0",
|
||||
"imports-loader": "0.6.5",
|
||||
"json-loader": "0.5.4",
|
||||
"lint-staged": "3.2.0",
|
||||
"mocha": "3.1.2",
|
||||
"node-sass": "^3.13.0",
|
||||
"null-loader": "0.1.1",
|
||||
"plop": "1.5.0",
|
||||
"postcss-cssnext": "^2.8.0",
|
||||
"postcss-focus": "^1.0.0",
|
||||
"postcss-loader": "^1.1.1",
|
||||
"postcss-reporter": "^2.0.0",
|
||||
"postcss-smart-import": "^0.6.7",
|
||||
"pre-commit": "1.1.3",
|
||||
"precss": "^1.4.0",
|
||||
"prettier": "^1.3.1",
|
||||
"psi": "2.0.4",
|
||||
"rimraf": "2.5.4",
|
||||
"sass-loader": "^4.0.2",
|
||||
"shelljs": "0.7.5",
|
||||
"sinon": "2.0.0-pre",
|
||||
"style-loader": "0.13.1",
|
||||
"url-loader": "0.5.7",
|
||||
"webpack": "2.1.0-beta.25",
|
||||
"webpack-dev-middleware": "1.8.4",
|
||||
"webpack-hot-middleware": "2.13.1"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user