Commit 58d43944 authored by Jure's avatar Jure

Merge branch 'split_server_and_client' into 'master'

feat: split server and client

See merge request !55
parents 284bebb5 749f12e0
Pipeline #13155 passed with stages
in 2 minutes and 50 seconds
**/_build
**/dist
**/node_modules
**/coverage
......@@ -86,7 +86,8 @@ api/db/*
.wallaby.js
logs
.env.*
_build
client/dist
server/dist
coverage/
yarn-error.log
package-lock.json
......
......@@ -4,9 +4,9 @@ FROM pubsweet/pubsweet:base
RUN curl -sL http://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN echo 'deb http://dl.google.com/linux/chrome/deb/ stable main' >> /etc/apt/sources.list.d/google.list
RUN apt-get update && apt-get install -y google-chrome-stable
# Apparently no debian package for firefox 57
# Apparently no debian package for firefox 64
RUN apt-get install -y libdbus-glib-1-2
RUN cd /opt && wget https://ftp.mozilla.org/pub/firefox/releases/64.0/linux-x86_64/en-GB/firefox-64.0.tar.bz2 && \
RUN cd /opt && wget https://ftp.mozilla.org/pub/firefox/releases/64.0.2/linux-x86_64/en-GB/firefox-64.0.2.tar.bz2 && \
tar xjf firefox-*.tar.bz2 && \
ln -s /opt/firefox/firefox /usr/local/bin/
......@@ -18,11 +18,11 @@ RUN [ "yarn", "cache", "clean"]
RUN [ "rm", "-rf", "/npm-packages-offline-cache"]
COPY .eslintignore .eslintrc .prettierrc ./
COPY app.js app.js
COPY static static
COPY public public
COPY app app
COPY scripts scripts
COPY config config
COPY app app
COPY server server
COPY test test
COPY webpack webpack
......
const logger = require('@pubsweet/logger')
const startServer = require('pubsweet-server')
startServer().catch(err => {
logger.error('FATAL ERROR, SHUTTING DOWN:', err)
process.exit(1)
})
......@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import { withRouter } from 'react-router-dom'
import { compose, withProps } from 'recompose'
import { AppBar, Action } from '@pubsweet/ui'
import logo from './pubsweet.jpg'
const Navigation = ({ logoutUser, currentUser, client }) => {
const links = [
......@@ -13,7 +14,7 @@ const Navigation = ({ logoutUser, currentUser, client }) => {
return (
<div>
<AppBar
brand={<img alt="pubsweet" src="/assets/pubsweet.jpg" />}
brand={<img alt="pubsweet" src={logo} />}
navLinkComponents={links}
onLogoutClick={() => logoutUser(client)}
user={currentUser}
......
......@@ -5,6 +5,6 @@
</head>
<body>
<div id="root"></div>
<script type="text/javascript" charset="utf-8" src="/assets/app.js"></script>
<script type="text/javascript" charset="utf-8" src="/assets/js/bundle.js"></script>
</body>
</html>
......@@ -3,5 +3,6 @@
"@pubsweet/model-team",
"@pubsweet/model-blog",
"@pubsweet/model-blogpost",
"@pubsweet/component-password-reset-server"
"@pubsweet/component-password-reset-server",
"@pubsweet/job-xsweet"
]
......@@ -5,7 +5,7 @@ const components = require('./components.json')
module.exports = {
'pubsweet-server': {
db: {
database: 'starter',
database: 'test',
},
logger,
port: 3000,
......
const { deferConfig } = require('config/defer')
module.exports = {
'pubsweet-server': {
db: {
database: 'starter',
},
baseUrl: deferConfig(
cfg => `http://localhost:${cfg['pubsweet-server'].port}`,
),
baseUrl: `http://localhost:4000`,
morganLogFormat:
':method :url :status :graphql[operation] :res[content-length] :response-time ms',
},
......
......@@ -2,6 +2,7 @@ module.exports = {
transport: {
sendmail: false,
port: 1025,
tls: { rejectUnauthorized: false },
auth: {
user: 'user',
pass: 'pass',
......
......@@ -13,6 +13,6 @@ module.exports = {
path: path.join(__dirname, 'mailer_test.js'),
},
'password-reset': {
url: 'http://localhost:4000/password-reset',
url: 'http://localhost:3000/password-reset',
},
}
......@@ -10,26 +10,27 @@
],
"main": "app.js",
"dependencies": {
"@pubsweet/coko-theme": "^5.1.0",
"@pubsweet/component-password-reset-client": "^3.0.7",
"@pubsweet/component-password-reset-server": "^2.0.3",
"@pubsweet/db-manager": "3.0.4",
"@pubsweet/default-theme": "4.0.13",
"@pubsweet/logger": "^0.2.18",
"@pubsweet/model-blog": "^0.0.11",
"@pubsweet/model-blogpost": "^0.0.11",
"@pubsweet/model-team": "^2.0.5",
"@pubsweet/model-user": "^4.0.5",
"@pubsweet/models": "0.2.5",
"@pubsweet/ui": "^10.2.0",
"@pubsweet/coko-theme": "^5.1.13",
"@pubsweet/component-password-reset-client": "^3.1.12",
"@pubsweet/component-password-reset-server": "^2.1.12",
"@pubsweet/db-manager": "3.0.17",
"@pubsweet/default-theme": "4.1.10",
"@pubsweet/job-xsweet": "^1.2.7",
"@pubsweet/logger": "^0.2.31",
"@pubsweet/model-blog": "^0.0.24",
"@pubsweet/model-blogpost": "^0.0.24",
"@pubsweet/model-team": "^2.1.1",
"@pubsweet/model-user": "^5.1.0",
"@pubsweet/models": "0.2.18",
"@pubsweet/ui": "^10.3.10",
"authsome": "^0.1.0",
"mini-css-extract-plugin": "^0.5.0",
"pubsweet": "^4.1.0",
"pubsweet-client": "^9.2.1",
"pubsweet-component-login": "^3.0.1",
"pubsweet-component-signup": "^2.0.1",
"pubsweet-server": "^13.3.0",
"xpub-edit": "^2.5.17"
"mini-css-extract-plugin": "^0.8.0",
"pubsweet": "^5.0.1",
"pubsweet-client": "^9.2.13",
"pubsweet-component-login": "^3.0.13",
"pubsweet-component-signup": "^2.1.7",
"pubsweet-server": "^13.6.1",
"xpub-edit": "^2.5.29"
},
"devDependencies": {
"@babel/core": "^7.0.0",
......@@ -70,26 +71,28 @@
"joi-browser": "^13.0.1",
"json-loader": "^0.5.4",
"lint-staged": "^6.1.0",
"node-dev": "^4.0.0",
"node-sass": "^4.5.2",
"objection": "^1.3.0",
"prettier": "^1.10.2",
"react-hot-loader": "^4.8.3",
"regenerator-runtime": "^0.11.0",
"script-loader": "^0.7.0",
"smtp-server": "^3.3.0",
"style-loader": "^0.23.1",
"testcafe": "^0.23.3",
"testcafe": "^1.4.2",
"testcafe-react-selectors": "^3.0.0",
"url-loader": "^1.1.2",
"webpack": "^4.29.6",
"webpack-hot-middleware": "^2.22.1"
"webpack": "^4.39.3",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2",
"webpack-hot-middleware": "^2.25.0"
},
"scripts": {
"lint": "eslint --ext js,jsx app config test webpack",
"start": "docker-compose up",
"server": "pubsweet server",
"start:services": "docker-compose up db",
"setupdb": "pubsweet setupdb",
"start:client": "pubsweet start:client",
"start:server": "pubsweet start:server",
"seed": "node scripts/seed.js",
"precommit": "lint-staged",
"test": "NODE_ENV=test NODE_PRESERVE_SYMLINKS=1 testcafe chrome 'test/**/*.test.js'"
......
The started application's server is entirely composed out of components (see `config/components.json`), so this folder is empty.
You can put your custom server components here (see the docs at https://pubsweet.coko.foundation/ for more information).
......@@ -25,15 +25,14 @@ module.exports = [
},
include: babelIncludes,
},
{ test: /\.png$/, loader: 'url-loader' },
{ test: /\.png|\.jpg$/, loader: 'url-loader' },
{
test: /\.woff|\.woff2|\.svg|.eot|\.ttf/,
loader: [
{
loader: 'url-loader',
options: {
prefix: 'font',
limit: 1000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
],
......@@ -61,9 +60,6 @@ module.exports = [
{
loader: MiniCssExtractPlugin.loader,
options: {
// you can specify a publicPath here
// by default it uses publicPath in webpackOptions.output
publicPath: '../',
hmr: process.env.NODE_ENV === 'development',
},
},
......
const path = require('path')
const config = require('config')
const webpack = require('webpack')
......@@ -17,15 +16,19 @@ module.exports = (opts = {}) => {
if (opts.html) {
plugins.push(
new HtmlWebpackPlugin({
title: 'PubSweet app',
title: 'PubSweet Starter App',
template: '../app/index.ejs', // Load a custom template
inject: 'body', // Inject all scripts into the body
}),
)
}
if (opts.extractText) {
plugins.push(new MiniCssExtractPlugin())
plugins.push(
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
}),
)
}
if (opts.noEmitOnErrors) {
......@@ -54,33 +57,11 @@ module.exports = (opts = {}) => {
}
plugins.push(
new CopyWebpackPlugin([{ from: '../static' }]),
new CopyWebpackPlugin([{ from: '../public' }]),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new CompressionPlugin(),
)
// These replacements are necessary until Atlaskit
// doesn't update to styled-components v4
plugins.push(
new webpack.NormalModuleReplacementPlugin(
/@atlaskit\/media-ui\/mixins.js/,
path.join(
__dirname,
'../app/components/CollabEditor/src/media-ui-mixins.js',
),
),
)
plugins.push(
new webpack.NormalModuleReplacementPlugin(
/@atlaskit\/editor-core\/plugins\/gap-cursor\/styles.js/,
path.join(
__dirname,
'../app/components/CollabEditor/src/gap-cursor-styles.js',
),
),
)
return plugins
}
const path = require('path')
const fs = require('fs-extra')
const config = require('config')
const { pick } = require('lodash')
const rules = require('./common-rules')
const contentBase = path.resolve(__dirname, '..', '_build', 'assets')
// can't use node-config in webpack so save whitelisted client config into the build and alias it below
const clientConfig = pick(config, config.publicKeys)
fs.ensureDirSync(contentBase)
const clientConfigPath = path.join(contentBase, 'client-config.json')
fs.writeJsonSync(clientConfigPath, clientConfig, { spaces: 2 })
const plugins = require('./plugins')
module.exports = webpackEnv => {
const isEnvDevelopment = webpackEnv === 'development'
const isEnvProduction = webpackEnv === 'production'
return {
devServer: {
port: 4000,
hot: true,
contentBase: path.join(contentBase, 'public'),
publicPath: '/',
proxy: {
'/api': 'http://localhost:3000',
'/graphql': 'http://localhost:3000',
},
historyApiFallback: true,
},
name: 'client application',
target: 'web',
mode: webpackEnv,
context: path.join(__dirname, '..', 'app'),
entry: {
app: isEnvDevelopment ? ['react-hot-loader/patch', './app'] : ['./app'],
},
output: {
path: contentBase,
publicPath: '/',
filename: isEnvProduction
? 'js/[name].[contenthash:8].js'
: isEnvDevelopment && 'js/bundle.js',
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'js/[name].chunk.js',
},
devtool: 'cheap-module-source-map',
module: {
rules,
},
resolve: {
alias: {
joi: 'joi-browser',
config: clientConfigPath,
},
extensions: ['.js', '.jsx', '.json', '.scss'],
enforceExtension: false,
},
plugins: plugins({
hmr: isEnvDevelopment,
html: true,
noEmitOnErrors: true,
extractText: isEnvProduction,
env: webpackEnv,
}),
}
}
const path = require('path')
const fs = require('fs-extra')
const config = require('config')
const { pick } = require('lodash')
const rules = require('./common-rules')
const outputPath = path.resolve(__dirname, '..', '_build', 'assets')
// can't use node-config in webpack so save whitelisted client config into the build and alias it below
const clientConfig = pick(config, config.publicKeys)
fs.ensureDirSync(outputPath)
const clientConfigPath = path.join(outputPath, 'client-config.json')
fs.writeJsonSync(clientConfigPath, clientConfig, { spaces: 2 })
const plugins = require('./plugins')
module.exports = [
{
// The configuration for the client
name: 'app',
target: 'web',
mode: 'development',
context: path.join(__dirname, '..', 'app'),
entry: {
app: ['react-hot-loader/patch', 'webpack-hot-middleware/client', './app'],
},
output: {
path: outputPath,
filename: '[name].js',
publicPath: '/assets/',
},
devtool: 'cheap-module-source-map',
module: {
rules,
},
resolve: {
alias: {
joi: 'joi-browser',
config: clientConfigPath,
},
extensions: ['.js', '.jsx', '.json', '.scss'],
enforceExtension: false,
},
plugins: plugins({
hmr: true,
html: false,
noEmitOnErrors: true,
extractText: false,
optimize: true,
env: 'development',
}),
node: {
fs: 'empty',
__dirname: true,
},
},
]
module.exports = require('./webpack.config.js')('development')
const path = require('path')
const fs = require('fs-extra')
const config = require('config')
const { pick } = require('lodash')
const rules = require('./common-rules')
const outputPath = path.resolve(__dirname, '..', '_build', 'assets')
// can't use node-config in webpack so save whitelisted client config into the build and alias it below
const clientConfig = pick(config, config.publicKeys)
fs.ensureDirSync(outputPath)
const clientConfigPath = path.join(outputPath, 'client-config.json')
fs.writeJsonSync(clientConfigPath, clientConfig, { spaces: 2 })
const plugins = require('./plugins')
module.exports = [
{
// The configuration for the client
name: 'app',
mode: 'production',
target: 'web',
context: path.join(__dirname, '..', 'app'),
entry: {
app: ['./app'],
},
output: {
path: outputPath,
filename: '[name].[hash].js',
publicPath: '/assets/',
},
module: {
rules,
},
resolve: {
alias: {
joi: 'joi-browser',
config: clientConfigPath,
},
extensions: ['.js', '.jsx', '.json', '.scss'],
},
plugins: plugins({
hmr: false,
html: true,
extractText: true,
optimize: true,
env: 'production',
}),
node: {
fs: 'empty',
__dirname: true,
},
},
]
module.exports = require('./webpack.config.js')('production')
const path = require('path')
const fs = require('fs-extra')
const config = require('config')
const { pick } = require('lodash')
const rules = require('./common-rules')
const outputPath = path.resolve(__dirname, '..', '_build', 'assets')
// can't use node-config in webpack so save whitelisted client config into the build and alias it below
const clientConfig = pick(config, config.publicKeys)
fs.ensureDirSync(outputPath)
const clientConfigPath = path.join(outputPath, 'client-config.json')
fs.writeJsonSync(clientConfigPath, clientConfig, { spaces: 2 })
const plugins = require('./plugins')
module.exports = [
{
// The configuration for the client
name: 'app',
mode: 'development',
target: 'web',
context: path.join(__dirname, '..', 'app'),
entry: {
app: ['react-hot-loader/patch', 'webpack-hot-middleware/client', './app'],
},
output: {
path: outputPath,
filename: '[name].js',
publicPath: '/assets/',
},
module: {
rules,
},
resolve: {
alias: {
joi: 'joi-browser',
config: clientConfigPath,
},
extensions: ['.js', '.jsx', '.json', '.scss'],
enforceExtension: false,
},
plugins: plugins({
hmr: true,
html: false,
noEmitOnErrors: true,
extractText: false,
optimize: true,
env: 'test',
}),
node: {
fs: 'empty',
__dirname: true,
},
},
]
module.exports = require('./webpack.config.js')('development')
This diff is collapsed.
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