+2
-1
@@ -62,9 +62,10 @@ FROM node:10.6-alpine as build-frontend
|
||||
|
||||
ARG CI
|
||||
ARG SKIP_FRONTEND_TEST
|
||||
ARG NODE_ENV=production
|
||||
|
||||
ADD web /srv/web
|
||||
COPY --from=build-frontend-deps /srv/web/node_modules /srv/web/node_modules
|
||||
ADD web /srv/web
|
||||
RUN cd /srv/web && \
|
||||
if [ -z "$SKIP_FRONTEND_TEST" ] ; then npx run-p lint test build ; \
|
||||
else echo "skip frontend tests and lint" ; npm run build ; fi && \
|
||||
|
||||
@@ -195,50 +195,9 @@ Admins/moderators should be defined in `docker-compose.yml` as a list of user ID
|
||||
To get user id just login and click on your username or any other user you want to promote to admins.
|
||||
It will expand login info and show full user ID.
|
||||
|
||||
### Setup on your website
|
||||
|
||||
### Frontend
|
||||
|
||||
Frontend part is building automatically along with backend if you use `docker-compose`.
|
||||
|
||||
For manual building:
|
||||
|
||||
* install [Node.js 8](https://nodejs.org/en/) or higher;
|
||||
* install [NPM 6.1.0](https://www.npmjs.com/package/npm) or higher;
|
||||
* run `npm install` inside `./web`;
|
||||
* run `npm run build` there;
|
||||
* result files will be saved in `./web/public`.
|
||||
|
||||
For development mode use `npm start` instead of `npm run build`.
|
||||
In this case `webpack` will serve files using `webpack-dev-server` on `localhost:8080`.
|
||||
|
||||
URLs for development:
|
||||
|
||||
* `localhost:8080` — page with embedded script from `REMARK_URL` (default: `https://demo.remark42.com`);
|
||||
* `localhost:8080/dev.html` — page with embedded script from local folder;
|
||||
* `localhost:8080/last-comments.html` — page with embedded script for last comments;
|
||||
* `localhost:8080/counter.html` — page with embedded script for counter with examples.
|
||||
|
||||
#### Testing
|
||||
|
||||
Also you can use fully functional local version to develop and test both frontend & backend.
|
||||
|
||||
To bring it up run:
|
||||
|
||||
```bash
|
||||
docker-compose -f compose-dev-frontend.yml build
|
||||
docker-compose -f compose-dev-frontend.yml up
|
||||
```
|
||||
|
||||
It starts Remark42 on `localhost:8080`
|
||||
and adds local OAuth2 provider “Dev”. To access UI demo page go to `localhost:8080/web`.
|
||||
|
||||
That `compose-dev.yml` (you can find it in the root of the project) also defines if default logged user admin or not.
|
||||
By default, it will be the admin, and to switch it to regular user comment or remove `-ADMIN=dev_user` there. You can also select
|
||||
any other user name from the login dialog.
|
||||
|
||||
#### Usage
|
||||
|
||||
##### Comments
|
||||
#### Comments
|
||||
|
||||
It's a main widget which renders list of comments.
|
||||
|
||||
@@ -305,7 +264,7 @@ Add this snippet to the bottom of web page:
|
||||
```html
|
||||
<script>
|
||||
var remark_config = {
|
||||
site_id: 'YOUR_SITE_ID',
|
||||
site_id: 'YOUR_SITE_ID',
|
||||
};
|
||||
|
||||
(function() {
|
||||
@@ -328,6 +287,62 @@ and it will use `data-url` attribute to define the page with comments.
|
||||
|
||||
Also script can uses `url` property from `remark_config` object, or `window.location.href` if nothing else is defined.
|
||||
|
||||
## Development
|
||||
|
||||
You can use fully functional local version to develop and test both frontend & backend.
|
||||
|
||||
To bring it up run:
|
||||
|
||||
```bash
|
||||
# if you mainly work on backend
|
||||
docker-compose -f compose-dev-backend.yml build
|
||||
docker-compose -f compose-dev-backend.yml up
|
||||
# if you mainly work on frontend
|
||||
docker-compose -f compose-dev-frontend.yml build
|
||||
docker-compose -f compose-dev-frontend.yml up
|
||||
```
|
||||
|
||||
It starts Remark42 on `127.0.0.1:8080` and adds local OAuth2 provider “Dev”.
|
||||
To access UI demo page go to `127.0.0.1:8080/web`.
|
||||
By default, you would be logged in as `dev_user` which defined as admin.
|
||||
You can tweak any of [supported parameters](#Parameters) in corresponded yml file.
|
||||
|
||||
Backend docker compose config by default skips running frontend related tests.
|
||||
Frontend docker compose config by default skips running backend related tests and sets `NODE_ENV=development` for frontend build.
|
||||
|
||||
### Backend
|
||||
|
||||
Maybe instructions for local build here?
|
||||
|
||||
### Frontend
|
||||
|
||||
#### Build
|
||||
|
||||
* install [Node.js 8](https://nodejs.org/en/) or higher;
|
||||
* install [NPM 6.1.0](https://www.npmjs.com/package/npm);
|
||||
* run `npm install` inside `./web`;
|
||||
* run `npm run build` there;
|
||||
* result files will be saved in `./web/public`.
|
||||
|
||||
**Note** Running `npm install` will set up precommit hooks into your git repository.
|
||||
It used to reformat your frontend code using `prettier` and lint with `eslint` before every commit.
|
||||
|
||||
#### Devserver
|
||||
|
||||
For local development mode with Hot Reloading use `npm start` instead of `npm run build`.
|
||||
In this case `webpack` will serve files using `webpack-dev-server` on `localhost:9000`.
|
||||
By visiting `127.0.0.1:9000/web` you will get a page with main comments widget.
|
||||
communicating with demo server backend running on `https://demo.remark42.com`.
|
||||
But you will not be able to login with any oauth providers due to security reasons.
|
||||
|
||||
You can attach to locally running backend by providing `REMARK_URL` environment variable.
|
||||
```sh
|
||||
npx cross-env REMARK_URL=http://127.0.0.1:8080 npm start
|
||||
```
|
||||
|
||||
Developer build running by `webpack-dev-server` supports devtools for [React](https://github.com/facebook/react-devtools) and
|
||||
[Redux](https://github.com/zalmoxisus/redux-devtools-extension).
|
||||
|
||||
## API
|
||||
|
||||
### Authorization
|
||||
@@ -472,7 +487,6 @@ Sort can be `time`, `active` or `score`. Supported sort order with prefix -/+, i
|
||||
|
||||
_all admin calls require auth and admin privilege_
|
||||
|
||||
|
||||
## Privacy
|
||||
|
||||
* Remark42 is trying to be very sensitive to any private or semi-private information.
|
||||
@@ -487,7 +501,6 @@ _all admin calls require auth and admin privilege_
|
||||
* Cookie lifespan can be restricted to session-only.
|
||||
* All potentially sensitive data stored by remark42 hashed and encrypted.
|
||||
|
||||
|
||||
## Technical details
|
||||
|
||||
* Data stored in [boltdb](https://github.com/coreos/bbolt) (embedded key/value database) files under `STORE_BOLT_PATH`
|
||||
@@ -500,8 +513,8 @@ _all admin calls require auth and admin privilege_
|
||||
* Request timeout set to 60sec
|
||||
* Development mode (`--dev-password` set) allows to test remark42 without social login and with admin privileges. Adds basic-auth for username: `dev`, password: `${DEV_PASSWD}`. **should not be used in production deployment**
|
||||
* User can vote for the comment multiple times but only to change the vote. Double-voting not allowed.
|
||||
* User can edit comments in 5 mins window after creation.
|
||||
* User can edit comments in 5 mins (configurable) window after creation.
|
||||
* User ID hashed and prefixed by oauth provider name to avoid collisions and potential abuse.
|
||||
* All avatars resized and cached locally to prevent rate limiters from google/github/facebook/yandex.
|
||||
* All avatars resized and cached locally to prevent rate limiters from oauth providers.
|
||||
* Images can be proxied (`IMG_PROXY=true`) to prevent mixed http/https.
|
||||
* Docker build uses [publicly available](https://github.com/umputun/baseimage) base images.
|
||||
|
||||
@@ -11,6 +11,7 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- SKIP_BACKEND_TEST=true
|
||||
# - NODE_ENV=development
|
||||
|
||||
image: umputun/remark42:dev
|
||||
container_name: "remark42-dev"
|
||||
@@ -38,6 +39,5 @@ services:
|
||||
- ADMIN=dev_user # set admin flag for default user on local ouath2
|
||||
volumes:
|
||||
- ./var:/srv/var
|
||||
# - ./web/public:/srv/web # uncomment to allow direct deployment of web parts
|
||||
|
||||
command: /srv/start.sh
|
||||
|
||||
@@ -36,6 +36,5 @@ services:
|
||||
# - DEV_PASSWD=password # development mode, be careful!
|
||||
volumes:
|
||||
- ./var:/srv/var
|
||||
#- ./web:/srv/web # uncomment to map web directory directly. It will propagate local changes to container without redeploy
|
||||
|
||||
command: /srv/start.sh
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
echo "prepare environment"
|
||||
|
||||
# replace base url by REMARK_URL
|
||||
sed -i "s|BASE_URL:\"[^\"]*\"|BASE_URL:\"${REMARK_URL}\"|g" /srv/web/*.js
|
||||
sed -i "s|var baseurl = '[^']*';|var baseurl = '${REMARK_URL}';|g" /srv/web/*.html
|
||||
# replace BASE_URL constant by REMARK_URL
|
||||
sed -i "s|https://demo.remark42.com|${REMARK_URL}|g" /srv/web/*.js
|
||||
# remove devtools attach helper. TODO: move to webpack loader
|
||||
sed -i "/REMOVE-START/,/REMOVE-END/d" /srv/web/iframe.html
|
||||
|
||||
echo "start remark42 server"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const BASE_URL = 'https://remark42.radio-t.com';
|
||||
const BASE_URL = process.env.REMARK_URL;
|
||||
const API_BASE = '/api/v1';
|
||||
const NODE_ID = 'remark42';
|
||||
const NODE_ID = process.env.REMARK_NODE;
|
||||
const COUNTER_NODE_CLASSNAME = 'remark42__counter';
|
||||
const COMMENT_NODE_CLASSNAME_PREFIX = 'remark42__comment-';
|
||||
const LAST_COMMENTS_NODE_CLASSNAME = 'remark42__last-comments';
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@ function init() {
|
||||
|
||||
node.innerHTML = `
|
||||
<iframe
|
||||
src="${process.env.NODE_ENV === 'production' ? `${BASE_URL}/web` : ''}/iframe.html?${query}"
|
||||
src="${BASE_URL}/web/iframe.html?${query}"
|
||||
width="100%"
|
||||
frameborder="0"
|
||||
allowtransparency="true"
|
||||
@@ -75,7 +75,7 @@ function init() {
|
||||
`&id=${user.id}&name=${user.name}&picture=${user.picture || ''}&isDefaultPicture=${user.isDefaultPicture || 0}`;
|
||||
this.node.innerHTML = `
|
||||
<iframe
|
||||
src="${process.env.NODE_ENV === 'production' ? `${BASE_URL}/web` : ''}/iframe.html?${queryUserInfo}"
|
||||
src="${BASE_URL}/web/iframe.html?${queryUserInfo}"
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameborder="0"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* eslint-disable no-console */
|
||||
/** @jsx h */
|
||||
import { h, render } from 'preact';
|
||||
import 'preact/debug';
|
||||
|
||||
import { BASE_URL, DEFAULT_LAST_COMMENTS_MAX, LAST_COMMENTS_NODE_CLASSNAME } from './common/constants';
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import loadPolyfills from 'common/polyfills';
|
||||
|
||||
import { h, render } from 'preact';
|
||||
import 'preact/debug';
|
||||
import { Provider } from 'preact-redux';
|
||||
import Root from './components/root';
|
||||
import UserInfo from 'components/user-info';
|
||||
|
||||
+5
-7
@@ -21,14 +21,14 @@
|
||||
<div class="container">
|
||||
<p>
|
||||
First counter with url from data-attribute:
|
||||
<span class="remark42__counter" data-url="https://radio-t.com/p/2017/11/11/podcast-571/"></span>
|
||||
(<a href="https://radio-t.com/p/2017/11/11/podcast-571/" target="_blank">note</a>)
|
||||
<span class="remark42__counter" data-url="http://127.0.0.1:8080/web/"></span>
|
||||
(<a href="http://127.0.0.1:8080/web/" target="_blank">note</a>)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Second counter with url from global remark config:
|
||||
<span class="remark42__counter"></span>
|
||||
(<a href="https://radio-t.com/p/2017/12/16/podcast-576/" target="_blank">note</a>)
|
||||
(<a href="http://127.0.0.1:8080/web/" target="_blank">note</a>)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -38,14 +38,12 @@
|
||||
|
||||
<script>
|
||||
var remark_config = {
|
||||
site_id: 'radiot',
|
||||
url: 'https://radio-t.com/p/2017/12/16/podcast-576/'
|
||||
site_id: 'remark',
|
||||
};
|
||||
|
||||
(function() {
|
||||
var d = document, s = d.createElement('script');
|
||||
var baseurl = '';
|
||||
s.src = baseurl + '/web/counter.js';
|
||||
s.src = '/web/counter.js';
|
||||
s.type = 'text/javascript';
|
||||
(d.head || d.body).appendChild(s);
|
||||
})();
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>remark42</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
margin: 40px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div id="remark42"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var remark_config = {
|
||||
site_id: 'radiot',
|
||||
url: 'https://radio-t.com/p/2017/12/16/podcast-576/',
|
||||
};
|
||||
|
||||
(function() {
|
||||
var d = document, s = d.createElement('script');
|
||||
s.src = '/embed.js';
|
||||
(d.head || d.body).appendChild(s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+8
-1
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
@@ -75,6 +75,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/* REMOVE-START */
|
||||
if (window.parent !== window) {
|
||||
try {
|
||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
} catch (e){}
|
||||
}
|
||||
/* REMOVE-END */
|
||||
var lastHeight = 0;
|
||||
setInterval(function() {
|
||||
if (document.body.offsetHeight !== lastHeight) {
|
||||
|
||||
+8
-2
@@ -19,6 +19,13 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Demo page</h1>
|
||||
<p>To install widgets on your website, follow the <a href="https://github.com/umputun/remark#setup-on-your-website">instructions</a>.</p>
|
||||
<p>See also</p>
|
||||
<ul>
|
||||
<li><a href="/web/last-comments.html">Last comments widget</a></li>
|
||||
<li><a href="/web/counter.html">Counter widget</a></li>
|
||||
</ul>
|
||||
<div id="remark42"></div>
|
||||
</div>
|
||||
|
||||
@@ -30,8 +37,7 @@
|
||||
|
||||
(function() {
|
||||
var d = document, s = d.createElement('script');
|
||||
var baseurl = 'https://demo.remark42.com/';
|
||||
s.src = baseurl + '/web/embed.js';
|
||||
s.src = '/web/embed.js';
|
||||
s.type = 'text/javascript';
|
||||
(d.head || d.body).appendChild(s);
|
||||
})();
|
||||
|
||||
@@ -24,13 +24,12 @@
|
||||
|
||||
<script>
|
||||
var remark_config = {
|
||||
site_id: 'radiot',
|
||||
site_id: 'remark',
|
||||
};
|
||||
|
||||
(function() {
|
||||
var d = document, s = d.createElement('script');
|
||||
var baseurl = '';
|
||||
s.src = baseurl + '/web/last-comments.js';
|
||||
s.src = '/web/last-comments.js';
|
||||
s.type = 'text/javascript';
|
||||
(d.head || d.body).appendChild(s);
|
||||
})();
|
||||
|
||||
Generated
+599
-203
File diff suppressed because it is too large
Load Diff
+5
-6
@@ -2,7 +2,7 @@
|
||||
"name": "remark-ui",
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production webpack --config ./webpack.config.js",
|
||||
"build": "webpack --config ./webpack.config.js",
|
||||
"start": "webpack-dev-server --progress --hot --inline --config ./webpack.config.js",
|
||||
"lint": "eslint --ext=.js,.jsx .",
|
||||
"test": "jest",
|
||||
@@ -30,8 +30,6 @@
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"clean-webpack-plugin": "^0.1.19",
|
||||
"copy-webpack-plugin": "^4.5.1",
|
||||
"core-js": "^2.5.7",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
@@ -54,9 +52,7 @@
|
||||
"postcss-simple-vars": "^4.1.0",
|
||||
"postcss-url": "^6.3.1",
|
||||
"postcss-wrap": "0.0.4",
|
||||
"preact-redux": "^2.0.3",
|
||||
"prettier": "^1.13.7",
|
||||
"redux": "^4.0.0",
|
||||
"style-loader": "^0.19.1",
|
||||
"webpack": "^3.12.0",
|
||||
"webpack-bundle-analyzer": "^2.13.1",
|
||||
@@ -65,7 +61,10 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"bem-react-helper": "^1.1.2",
|
||||
"preact": "^8.2.9"
|
||||
"core-js": "^2.5.7",
|
||||
"preact": "^8.2.9",
|
||||
"preact-redux": "^2.0.3",
|
||||
"redux": "^4.0.0"
|
||||
},
|
||||
"eslintIgnore": [
|
||||
"public"
|
||||
|
||||
+27
-23
@@ -11,12 +11,13 @@ const Define = webpack.DefinePlugin;
|
||||
const BundleAnalyze = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
const babelOptions = require('./babelOptions');
|
||||
const { NODE_ID } = require('./app/common/constants');
|
||||
const publicFolder = path.resolve(__dirname, 'public');
|
||||
const env = process.env.NODE_ENV || 'dev';
|
||||
|
||||
const env = process.env.NODE_ENV || 'development';
|
||||
const remarkUrl = process.env.REMARK_URL || 'https://demo.remark42.com';
|
||||
const NODE_ID = 'remark42';
|
||||
// let's log some env variables because we can
|
||||
console.log(`NODE_ENV = ${env}`);
|
||||
console.log(`REMARK_ENV = ${process.env.REMARK_URL}`);
|
||||
|
||||
const commonStyleLoaders = [
|
||||
'css-loader',
|
||||
@@ -39,6 +40,7 @@ const commonStyleLoaders = [
|
||||
|
||||
module.exports = {
|
||||
context: __dirname,
|
||||
devtool: env === 'development' ? 'source-map' : false,
|
||||
entry: {
|
||||
embed: './app/embed',
|
||||
counter: './app/counter',
|
||||
@@ -66,13 +68,10 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use:
|
||||
env === 'production'
|
||||
? ExtractText.extract({
|
||||
fallback: 'style-loader',
|
||||
use: commonStyleLoaders,
|
||||
})
|
||||
: ['style-loader', ...commonStyleLoaders],
|
||||
use: ExtractText.extract({
|
||||
fallback: 'style-loader',
|
||||
use: commonStyleLoaders,
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|jpeg|gif|svg)$/,
|
||||
@@ -91,7 +90,9 @@ module.exports = {
|
||||
b: 'bem-react-helper',
|
||||
}),
|
||||
new Define({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
'process.env.NODE_ENV': JSON.stringify(env),
|
||||
'process.env.REMARK_NODE': JSON.stringify(NODE_ID),
|
||||
'process.env.REMARK_URL': env === 'production' ? JSON.stringify(remarkUrl) : 'window.location.origin',
|
||||
}),
|
||||
// TODO: we should add it only on demo serv
|
||||
new Html({
|
||||
@@ -110,15 +111,6 @@ module.exports = {
|
||||
filename: 'last-comments.html',
|
||||
inject: false,
|
||||
}),
|
||||
...(env === 'production'
|
||||
? []
|
||||
: [
|
||||
new Html({
|
||||
template: path.resolve(__dirname, 'dev.ejs'),
|
||||
filename: 'dev.html',
|
||||
inject: false,
|
||||
}),
|
||||
]),
|
||||
new ExtractText({
|
||||
filename: `remark.css`,
|
||||
allChunks: true,
|
||||
@@ -139,13 +131,25 @@ module.exports = {
|
||||
]),
|
||||
new Copy(['./iframe.html']),
|
||||
],
|
||||
watch: env === 'dev',
|
||||
watchOptions: {
|
||||
ignored: /(node_modules|\.vendor\.js$)/,
|
||||
},
|
||||
devServer: {
|
||||
host: '0.0.0.0',
|
||||
port: 8080,
|
||||
host: 'localhost',
|
||||
port: 9000,
|
||||
contentBase: publicFolder,
|
||||
publicPath: '/web',
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: remarkUrl,
|
||||
logLevel: 'debug',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/auth': {
|
||||
target: remarkUrl,
|
||||
logLevel: 'debug',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user