Commit 9b5ffb07 authored by Jure's avatar Jure

Merge branch 'webpack_compile' into 'master'

Use pubsweet-core as a dependency (and get webpack to play along)



See merge request !1
parents 79c09338 d44e748b
// Use this file as a starting point for your project's .eslintrc.
// Copy this file, and add rule overrides as needed.
{
"extends": ["standard", "standard-react"],
"ecmaFeatures": {
"jsx": true
},
"plugins": [
"react"
]
}
.DS_Store
node_modules/
api/db/*
public/assets/*
# Science Blogger
Powered by PubSweet.
# Preconditions
Node.js, version above or equal to 4.0.0, is a requirement, read about how to install it here: [https://nodejs.org/en/](https://nodejs.org/en/)
Warning about `npm`: Because the newly released npm 3 changed the way npm installs nested dependencies (it flattens them), and we rely on previous behaviour (https://github.com/npm/npm/issues/9809) please use npm 2.x while we work on resolving this.
# Install
```bash
$ git clone git@gitlab.coko.foundation:pubsweet/science-blogger.git
$ cd science-blogger
$ npm install
```
# Start the server
First, initialize your blog by running and going through the setup process:
```bash
$ NODE_ENV=dev npm run setup
```
To start the JS compilation and webserver, run:
```bash
$ npm run dev
```
Point your browser to: http://localhost:3000/manage/posts and login with the chosen admin username and password and all should be well. Visit http://localhost:3000 for the blog landing page.
# Themes
Themes are a PubSweet component. If you want to write a custom theme, set your theme component in `config.js`. When you require a style from a component, using e.g. `import './Signup.scss'` in `app/components/Signup/Signup.jsx`, we'll automatically find the right themed style (e.g. `app/components/PepperTheme/Signup/Signup.scss` if theme is set to `PepperTheme`). You can then continue working on your themed styles as usual, and the page will hot-reload when you change anything.
# How to look into the database for debugging purposes
Run a PouchDB server (comes with the app):
```bash
$ npm run pouchdb
```
And navigate to [http://localhost:5984/_utils/](http://localhost:5984/_utils/). Click "Add New Database" and enter "dev", to connect to the development database. You should now be able to run queries on your development database.
# Production installation
These are instructions for Ubuntu 15.10, exact steps may vary from OS to OS so if you're using another system, please take this as general guidance only.
First [install node 4.x](https://github.com/nodesource/distributions#debinstall)
```bash
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
sudo apt-get install -y nodejs
```
Then clone the repository:
```bash
git clone https://gitlab.coko.foundation/pubsweet/science-blogger.git
```
Install the required npm modules:
```bash
npm install
```
Build the production JS:
```bash
npm run build
```
Configure your initial admin account:
```bash
NODE_ENV=production npm run setup
```
Start the server:
```bash
npm run start
```
The application should now be accessible through port 80 on your server.
import React from 'react'
import configureStore from './store/configureStore'
import { render } from 'react-dom'
import Root from './containers/Root'
import React from 'pubsweet-core/node_modules/react'
import ReactDOM from 'pubsweet-core/node_modules/react-dom'
let store = configureStore()
import configureStore from 'pubsweet-core/app/store/configureStore'
import Root from 'pubsweet-core/app/components/Root'
render(
<Root store={store} />,
document.getElementById('root')
import { AppContainer } from 'pubsweet-core/node_modules/react-hot-loader'
import { browserHistory } from 'pubsweet-core/node_modules/react-router'
import { syncHistoryWithStore } from 'pubsweet-core/node_modules/react-router-redux'
let store = configureStore(browserHistory, {})
let history = syncHistoryWithStore(browserHistory, store)
const rootEl = document.getElementById('root')
ReactDOM.render(
<AppContainer>
<Root store={store} history={history}/>
</AppContainer>,
rootEl
)
if (module.hot) {
module.hot.accept('pubsweet-core/app/components/Root', () => {
const NextRoot = require('pubsweet-core/app/components/Root').default
ReactDOM.render(
<AppContainer>
<NextRoot store={store} history={history}/>
</AppContainer>,
rootEl
)
})
}
import React from 'pubsweet-core/node_modules/react'
import { LinkContainer } from 'pubsweet-core/node_modules/react-router-bootstrap'
import { Navbar, Nav, NavItem, NavbarBrand } from 'pubsweet-core/node_modules/react-bootstrap'
import AuthHelper from 'pubsweet-core/app/helpers/AuthHelper'
import NavbarUser from 'pubsweet-core/app/components/Navigation/NavbarUser'
export default class Navigation extends React.Component {
render () {
const { actions, auth } = this.props
let logoutButtonIfAuthenticated
if (auth.isAuthenticated) {
logoutButtonIfAuthenticated = <NavbarUser
roles={auth.roles}
username={auth.username}
switchRole={actions.switchRole}
onLogoutClick={actions.logoutUser}
/>
}
return (
<Navbar fluid>
<Navbar.Header>
<NavbarBrand>
<a href='#'><img src='/pubsweet.jpg' alt='science'/></a>
</NavbarBrand>
</Navbar.Header>
<Nav eventKey={0}>
<LinkContainer to='/manage/posts'>
<NavItem>Science Posts</NavItem>
</LinkContainer>
{ AuthHelper.showForUser(auth, 'users') &&
<LinkContainer to='/manage/users'>
<NavItem>Users</NavItem>
</LinkContainer>
}
</Nav>
{ logoutButtonIfAuthenticated }
</Navbar>
)
}
}
Navigation.propTypes = {
actions: React.PropTypes.object.isRequired,
auth: React.PropTypes.object
}
import React from 'react'
import { Route } from 'react-router'
import React from 'pubsweet-core/node_modules/react'
import { Route } from 'pubsweet-core/node_modules/react-router'
import { requireAuthentication } from './containers/AuthenticatedComponent'
import { requireAuthentication } from 'pubsweet-core/app/components/AuthenticatedComponent'
// Manage
import Manage from './containers/Manage'
import PostsManager from './containers/PostsManager'
import Editor from './containers/EditorWrapper'
import UsersManager from './containers/UsersManager'
import Manage from 'pubsweet-core/app/components/Manage/Manage'
import PostsManager from 'pubsweet-core/app/components/PostsManager/PostsManager'
import ScienceWriter from 'pubsweet-core/app/components/ScienceWriter/ScienceWriter'
import UsersManager from 'pubsweet-core/app/components/UsersManager/UsersManager'
// Public
import Blog from './containers/Blog'
import Blogpost from './containers/BlogpostWrapper'
import Blog from 'pubsweet-core/app/components/Blog/Blog'
import ScienceReader from 'pubsweet-core/app/components/ScienceReader/ScienceReader'
// Authentication
import Login from './components/Login'
import Signup from './components/Signup'
import Login from 'pubsweet-core/app/components/Login/Login'
import Signup from 'pubsweet-core/app/components/Signup/Signup'
export default (
<Route>
......@@ -23,12 +23,12 @@ export default (
<Route path='/manage' component={requireAuthentication(Manage)}>
<Route path='posts' component={PostsManager} />
<Route path='editor/:id' component={Editor} />
<Route path='sciencewriter/:id' component={ScienceWriter} />
<Route path='users' component={UsersManager} />
</Route>
<Route path='/login' component={Login} />
<Route path='/signup' component={Signup} />
<Route path='/:id' component={Blogpost}/>
<Route path='/:id' component={ScienceReader}/>
</Route>
)
const api = require('pubsweet-core/api/api')
const http = require('http')
// Get port from environment or default to 3000
var port = process.env.PORT || '3000'
api.set('port', port)
var server = http.createServer(api)
server.listen(port)
server.on('error', onError)
server.on('listening', onListening)
function onError (error) {
throw error
}
function onListening () {
var addr = server.address()
console.log('PubSweet is listening on ' + addr.port)
}
module.exports = {
secret: 'EXAMPLEDONTUSE',
API_ENDPOINT: '/api',
editor: '../registry/Substance/Writer.jsx',
// editor: '../registry/Quill/Editor.jsx',
reader: '../registry/Substance/Reader.jsx',
// reader: '../registry/Quill/Reader.jsx'
theme: 'pepper'
theme: 'PepperTheme',
routes: 'app/routes.jsx',
navigation: 'app/components/Navigation/Navigation.jsx'
}
{
"name": "science-blogger",
"version": "1.0.0-alpha",
"version": "1.0.0-alpha.2",
"private": true,
"scripts": {
"setup": "node api/setup.js",
"setup": "node node_modules/pubsweet-core/api/setup.js",
"build": "webpack --colors --config ./webpack/webpack.prod.config.js",
"start": "PORT=80 NODE_ENV=production node bin/www",
"dev": "NODE_ENV=dev LOADER=hot node bin/www",
......@@ -12,7 +12,25 @@
"eslint": "eslint"
},
"dependencies": {
"core": "git+https://gitlab.coko.foundation/pubsweet/core.git#master"
"pubsweet-core": "git+https://gitlab.coko.foundation/pubsweet/core.git#7a8e4ee"
},
"devDependencies": {
"babel-core": "^6.3.0",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-2": "^6.5.0",
"eslint": "^1.10.3",
"eslint-config-standard": "^4.4.0",
"eslint-config-standard-react": "^1.2.1",
"eslint-loader": "^1.2.0",
"eslint-plugin-react": "^3.14.0",
"eslint-plugin-standard": "^1.1.0",
"extract-text-webpack-plugin": "^1.0.1",
"style-loader": "^0.12.3",
"webpack": "^1.12.14",
"webpack-dev-middleware": "^1.6.1",
"webpack-hot-middleware": "^2.10.0"
},
"standard": {
"parser": "babel-eslint"
......
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require('../../../node_modules/core/node_modules/react');
var _react2 = _interopRequireDefault(_react);
var _reactRouterBootstrap = require('../../../node_modules/core/node_modules/react-router-bootstrap');
var _reactBootstrap = require('../../../node_modules/core/node_modules/react-bootstrap');
var _AuthHelper = require('../../../node_modules/core/app/helpers/AuthHelper');
var _AuthHelper2 = _interopRequireDefault(_AuthHelper);
var _NavbarUser = require('../../../node_modules/core/app/components/Navigation/NavbarUser');
var _NavbarUser2 = _interopRequireDefault(_NavbarUser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var Navigation = function (_React$Component) {
_inherits(Navigation, _React$Component);
function Navigation() {
_classCallCheck(this, Navigation);
return _possibleConstructorReturn(this, Object.getPrototypeOf(Navigation).apply(this, arguments));
}
_createClass(Navigation, [{
key: 'render',
value: function render() {
var _props = this.props;
var actions = _props.actions;
var auth = _props.auth;
var logoutButtonIfAuthenticated = void 0;
if (auth.isAuthenticated) {
logoutButtonIfAuthenticated = _react2.default.createElement(_NavbarUser2.default, {
roles: auth.roles,
username: auth.username,
switchRole: actions.switchRole,
onLogoutClick: actions.logoutUser
});
}
return _react2.default.createElement(
_reactBootstrap.Navbar,
{ fluid: true },
_react2.default.createElement(
_reactBootstrap.Navbar.Header,
null,
_react2.default.createElement(
_reactBootstrap.NavbarBrand,
null,
_react2.default.createElement(
'a',
{ href: '#' },
_react2.default.createElement('img', { src: '/science.png', alt: 'science' })
)
)
),
_react2.default.createElement(
_reactBootstrap.Nav,
{ eventKey: 0 },
_react2.default.createElement(
_reactRouterBootstrap.LinkContainer,
{ to: '/manage/posts' },
_react2.default.createElement(
_reactBootstrap.NavItem,
null,
'Science Posts'
)
),
'p',
_AuthHelper2.default.showForUser(auth, 'users') && _react2.default.createElement(
_reactRouterBootstrap.LinkContainer,
{ to: '/manage/users' },
_react2.default.createElement(
_reactBootstrap.NavItem,
null,
'Users'
)
),
_react2.default.createElement(
_reactRouterBootstrap.LinkContainer,
{ to: '/manage/users' },
_react2.default.createElement(
_reactBootstrap.NavItem,
null,
'She\'s alive!'
)
)
),
logoutButtonIfAuthenticated
);
}
}]);
return Navigation;
}(_react2.default.Component);
exports.default = Navigation;
Navigation.propTypes = {
actions: _react2.default.PropTypes.object.isRequired,
auth: _react2.default.PropTypes.object
};
var path = require('path')
var webpack = require('webpack')
var config = require('../config')
var ThemeResolver = require('./ThemeResolver')
var ThemeResolver = require('pubsweet-core/webpack/ThemeResolver')
var assetsPath = path.join(__dirname, '..', 'public', 'assets')
var publicPath = '/assets/'
......@@ -9,20 +9,17 @@ var publicPath = '/assets/'
// but excluding its node_modules.
var commonLoaders = [
{
/*
* TC39 categorises proposals for babel in 4 stages
* Read more http://babeljs.io/docs/usage/experimental/
*/
test: /\.js$|\.jsx$/,
loader: 'babel',
// Reason why we put this here instead of babelrc
// https://github.com/gaearon/react-transform-hmr/issues/5#issuecomment-142313637
query: {
'presets': ['react-hmre', 'es2015', 'react'],
'cacheDirectory': true
presets: ['es2015', 'react', 'stage-2'],
plugins: ['pubsweet-core/node_modules/react-hot-loader/babel']
},
include: path.join(__dirname, '..', 'app'),
exclude: path.join(__dirname, '/node_modules/')
include: [
new RegExp(path.join(__dirname, '../node_modules/pubsweet-core/app')),
new RegExp(path.join(__dirname, '../app')),
new RegExp(path.join(__dirname, '../../core/app')) // TODO: Temp while linked.
]
},
{ test: /\.png$/, loader: 'url-loader' },
{
......@@ -50,8 +47,9 @@ module.exports = [
context: path.join(__dirname, '..', 'app'),
entry: {
app: [
'./app',
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true'
'pubsweet-core/node_modules/react-hot-loader/patch',
'webpack-hot-middleware/client',
'./app'
]
},
output: {
......@@ -72,10 +70,11 @@ module.exports = [
loaders: commonLoaders
},
resolve: {
root: path.resolve(__dirname, '..'),
extensions: ['', '.js', '.jsx', '.json', '.scss'],
alias: {
'editor$': config.editor,
'reader$': config.reader
'routes$': config.routes,
'navigation$': config.navigation
}
},
plugins: [
......
var path = require('path')
var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ThemeResolver = require('./ThemeResolver')
var config = require('../config')
var ExtractTextPlugin = require('pubsweet-core/node_modules/extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('pubsweet-core/node_modules/html-webpack-plugin')
var ThemeResolver = require('pubsweet-core/webpack/ThemeResolver')
var assetsPath = path.join(__dirname, '..', 'public', 'assets')
var publicPath = '/assets/'
......@@ -12,20 +11,17 @@ var publicPath = '/assets/'
// but excluding its node_modules.
var commonLoaders = [
{
/*
* TC39 categorises proposals for babel in 4 stages
* Read more http://babeljs.io/docs/usage/experimental/
*/
test: /\.js$|\.jsx$/,
loader: 'babel',
// Reason why we put this here instead of babelrc
// https://github.com/gaearon/react-transform-hmr/issues/5#issuecomment-142313637
query: {
'presets': ['es2015', 'react'],
'cacheDirectory': true
presets: ['es2015', 'react', 'stage-2'],
plugins: ['pubsweet-core/node_modules/react-hot-loader/babel']
},
include: path.join(__dirname, '..', 'app'),
exclude: path.join(__dirname, '/node_modules/')
include: [
new RegExp(path.join(__dirname, '../node_modules/pubsweet-core/app')),
new RegExp(path.join(__dirname, '../app')),
new RegExp(path.join(__dirname, '../../core/app')) // TODO: Temp while linked.
]
},
{ test: /\.png$/, loader: 'url-loader' },
{
......@@ -42,6 +38,7 @@ var commonLoaders = [
include: /\.local\.s?css/, // Local styles
loader: 'style-loader!css-loader?modules&importLoaders=1!sass-loader'
}
]
module.exports = [
......@@ -51,35 +48,35 @@ module.exports = [
target: 'web',
context: path.join(__dirname, '..', 'app'),
entry: {
app: [ './app' ]
app: [
'./app'
]
},
output: {
// The output directory as absolute path
path: assetsPath,
// The filename of the entry chunk as relative path inside the output.path directory
filename: '[name]-[hash].js',
// The output path from the view of the Javascript
publicPath: publicPath
},
module: {
preLoaders: [{
test: /\.js$|\.jsx$/,
exclude: [/node_modules/, /\/lens/, /\/substance/],
exclude: [/\/node_modules/, /\/lens/, /\/substance/],
loaders: ['eslint-loader']
}],
loaders: commonLoaders
},
resolve: {
root: path.resolve(__dirname, '..'),
extensions: ['', '.js', '.jsx', '.json', '.scss'],
alias: {
'editor$': config.editor,
'reader$': config.reader
'routes$': config.routes,
'navigation$': config.navigation
}
},
plugins: [
new webpack.ResolverPlugin([ThemeResolver], ['normal', 'context', 'loader']),
new HtmlWebpackPlugin({
title: 'PubSweet',
title: 'PubSweet Science Blogger',
template: '../app/index.ejs', // Load a custom template
inject: 'body' // Inject all scripts into the body
}),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment