├── .babelrc
├── .gitignore
├── LICENSE
├── README.md
├── api
├── database.js
└── routes.js
├── client
└── src
│ ├── components
│ ├── app.js
│ ├── endpoint-controls.js
│ ├── footer.js
│ └── navigator.js
│ ├── html.js
│ ├── index.js
│ ├── public
│ ├── css
│ │ └── main.css
│ ├── favicon.png
│ ├── index.html
│ └── js
│ │ └── drift.js
│ └── services
│ └── appService.js
├── logo.png
├── package-lock.json
├── package.json
├── server.js
├── webpack.config.js
└── webpack.config.prod.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"],
3 | "plugins": [
4 | "transform-react-jsx",
5 | "transform-class-properties"
6 | ]
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Eliran Pe'er
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Start storing your data in the cloud in 2 seconds
14 |
15 |
16 | ## jsonstore.io
17 | jsonstore.io offers a free, secured and JSON based cloud datastore for small projects.
18 | Just enter https://www.jsonstore.io/, copy the URL and start sending HTTP requests to communicate with your datastore.
19 | POST requests will save data, PUT requests modify data, DELETE requests delete data and GET requests retrieves data.
20 |
21 | ## Examples
22 | Make sure to replace the URL in the examples to your own endpoint, that can be found at https://www.jsonstore.io/.
23 | ### CURL
24 | #### POST
25 | The following command will create a user in `/users/1`:
26 | ```shell
27 | curl -XPOST -H "Content-type: application/json" -d '{
28 | "name": "jon.snow",
29 | "age": 31
30 | }' 'https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users/1'
31 | ```
32 |
33 | #### GET
34 | The following command will retrieve the user we created earlier:
35 | ```shell
36 | curl -XGET 'https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users/1'
37 | ```
38 |
39 | ##### Querying and Sorting
40 | To query the data, use the query parameters `orderKey`, `filterValue` and `valueType`
41 |
42 | - `orderKey`: name of the key in child. For example, to order by `age` use,
43 | ```shell
44 | curl -XGET 'https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users?orderKey=age'
45 | ```
46 |
47 | > if `orderKey` in not present in child, that child will come in order before children with `orderKey`
48 |
49 | - `filterValue`: value of key (given using `orderKey`), to filter the children by. For example, to get the users with `age`=`20`
50 | ```shell
51 | curl -XGET 'https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users?orderKey=age&filterValue=20'
52 | ```
53 | > `filterValue` should be used in conjugation with `orderBy`.
54 |
55 | - `valueType`: enforcing type of `filterValue`. Type of `filterValue` is guessed by `jsonstore`. If you want to enforce a type, send `string`, `number` or `boolean` as `valueType`. For eg,
56 | ```shell
57 | curl -XGET 'https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users?orderKey=age&filterValue=20&valueType=number'
58 | ```
59 |
60 | #### PUT
61 | The following command will change the age of the user to `32`:
62 | ```shell
63 | curl -XPUT -H "Content-type: application/json" -d '32' 'https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users/1/age'
64 | ```
65 |
66 | #### DELETE
67 | The following command will delete the user:
68 | ```shell
69 | curl -XDELETE 'https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users/1'
70 | ```
71 |
72 | ### JavaScript
73 | #### POST
74 | ```js
75 | fetch('https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users/1', {
76 | headers: {
77 | 'Content-type': 'application/json'
78 | },
79 | method: 'POST',
80 | body: { name: 'jon snow', age: 31 },
81 | });
82 | ```
83 |
84 | #### GET
85 | ```js
86 | const user = await fetch('https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users/1')
87 | .then(function(response) {
88 | return response.json();
89 | })
90 | ```
91 |
92 | #### PUT
93 | ```js
94 | fetch('https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users/1/age', {
95 | headers: {
96 | 'Content-type': 'application/json'
97 | },
98 | method: 'PUT',
99 | body: 32,
100 | });
101 | ```
102 |
103 | #### DELETE
104 | ```js
105 | fetch('https://www.jsonstore.io/cf024bb815a93131ce9fed91b1f9dafa43a3c557e9be66e66fd76df5c64f10fe/users/1', {
106 | method: 'DELETE',
107 | });
108 | ```
109 |
110 | ### Contribution
111 | Any type of feedback, pull request or issue is welcome.
112 |
--------------------------------------------------------------------------------
/api/database.js:
--------------------------------------------------------------------------------
1 | const firebase = require('firebase');
2 |
3 | function guessType(value) {
4 | const number = /^-?\d*\.?\d*$/;
5 | const boolean = /(true|false)/;
6 |
7 | if (number.test(value)) {
8 | return Number;
9 | }
10 |
11 | if (boolean.test(value)) {
12 | return JSON.parse;
13 | }
14 |
15 | return ((v) => v);
16 | }
17 |
18 | function convert(value, type) {
19 | const typemap = {
20 | 'number': Number,
21 | 'boolean': Boolean,
22 | 'string': String,
23 | };
24 | const converter = typemap[type] || guessType(value);
25 | return converter(value);
26 | }
27 |
28 |
29 | if (!process.env.FIREBASE_CONFIG) {
30 | module.exports = {
31 | get: () => (console.log(arguments), Promise.resolve()),
32 | post: () => (console.log(arguments), Promise.resolve()),
33 | put: () => (console.log(arguments), Promise.resolve()),
34 | delete: () => (console.log(arguments), Promise.resolve()),
35 | }
36 | } else {
37 | const config = JSON.parse(process.env.FIREBASE_CONFIG);
38 | firebase.initializeApp(config);
39 |
40 | module.exports = {
41 | get: (key, orderKey, filterValue, valueType) => {
42 | let ref = firebase.database().ref(key);
43 |
44 | if (orderKey) {
45 | ref = ref.orderByChild(orderKey);
46 | if (filterValue !== undefined) {
47 | ref = ref.equalTo(convert(filterValue, valueType));
48 | }
49 | }
50 | return ref
51 | .once('value')
52 | .then(snapshot => {
53 | if (!orderKey) {
54 | return snapshot.val();
55 | }
56 |
57 | const data = [];
58 | // snapshot.val() forgets any ordering info
59 | snapshot.forEach(item => {
60 | if (item.val()) {
61 | data.push(item.val());
62 | }
63 | });
64 | return data;
65 | });
66 | },
67 |
68 | post: (key, data) =>
69 | firebase
70 | .database()
71 | .ref(key)
72 | .set(data),
73 |
74 | put: (key, data) =>
75 | firebase
76 | .database()
77 | .ref()
78 | .update({
79 | [key]: data,
80 | }),
81 |
82 | delete: key =>
83 | firebase
84 | .database()
85 | .ref(key)
86 | .remove(),
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/api/routes.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const crypto = require('crypto');
3 | const database = require('./database');
4 | const { URL } = require('url');
5 |
6 | function checkContentType(req, res, next) {
7 | if (!req.is('application/json')) {
8 | return res.status(400).send({ ok: false, error: "Bad request" });
9 | }
10 |
11 | next();
12 | }
13 |
14 | const router = express.Router();
15 |
16 | router.get('/get-token', (req, res) => {
17 | const seed = crypto.randomBytes(64);
18 | const hash = crypto.createHash('sha256').update(seed).digest('hex');
19 | return res.send({ token: hash });
20 | });
21 |
22 | router.get(/^\/[0-9a-z]{64}/, (req, res) => {
23 | const { orderKey, filterValue, valueType } = req.query;
24 |
25 | database
26 | .get(req.path, orderKey, filterValue, valueType)
27 | .then(result => res.status(200).send({ result, ok: true }))
28 | .catch(() => res.status(500).send({ ok: false }))
29 | });
30 |
31 | router.post(/^\/[0-9a-z]{64}/, checkContentType, (req, res) =>
32 | database
33 | .post(req.path, req.body)
34 | .then(() => res.status(201).send({ ok: true }))
35 | .catch(() => res.status(500).send({ ok: false }))
36 | )
37 |
38 | router.put(/^\/[0-9a-z]{64}/, checkContentType, (req, res) =>
39 | database
40 | .put(req.path, req.body)
41 | .then(() => res.status(200).send({ ok: true }))
42 | .catch(() => res.status(500).send({ ok: false }))
43 | );
44 |
45 | router.delete(/^\/[0-9a-z]{64}/, (req, res) =>
46 | database
47 | .delete(req.path, req.body)
48 | .then(() => res.status(200).send({ ok: true }))
49 | .catch(() => res.status(500).send({ ok: false }))
50 | );
51 |
52 | module.exports = router;
53 |
--------------------------------------------------------------------------------
/client/src/components/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Navigator from './navigator';
4 | import EndpointControls from './endpoint-controls';
5 | import Footer from './footer';
6 |
7 | const App = () =>
8 |
9 |
10 |
11 |
12 |
13 |
14 | export default App;
--------------------------------------------------------------------------------
/client/src/components/endpoint-controls.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AppService from './../services/appService';
3 |
4 | class EndpointControls extends React.Component {
5 | state = {
6 | loading: true
7 | }
8 |
9 | async componentWillMount() {
10 | const appService = new AppService();
11 |
12 | this.setState({
13 | loading: false,
14 | token: await appService.getToken(),
15 | })
16 | }
17 |
18 | copyUrl() {
19 | this.refs.urlInput.select();
20 | document.execCommand('copy');
21 | }
22 |
23 | componentDidMount() {
24 | this.refs.urlInput.select();
25 | }
26 |
27 | render() {
28 | let endpoint = null;
29 | if (!this.state.loading) {
30 | if (location.port) {
31 | endpoint = `${location.protocol}//${location.hostname}:${location.port}/${this.state.token}`;
32 | } else {
33 | endpoint = `${location.protocol}//${location.hostname}/${this.state.token}`;
34 | }
35 | }
36 | return ();
64 | }
65 | }
66 |
67 |
68 | export default EndpointControls;
--------------------------------------------------------------------------------
/client/src/components/footer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Footer = () =>
4 |
5 | Made with
6 | by
7 | @bluzi
8 |
9 |
10 | export default Footer;
--------------------------------------------------------------------------------
/client/src/components/navigator.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Navigator = () =>
4 |
5 |
27 |
28 |
29 | export default Navigator;
--------------------------------------------------------------------------------
/client/src/html.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import App from './components/app';
3 |
4 | const Html = () =>
5 |
6 |
7 | jsonstore.io / Store your data just by sending us HTTP Requests
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | ;
25 |
26 | export default Html;
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import 'babel-polyfill';
2 |
3 | import App from './components/app';
4 | import React from 'react';
5 | import ReactDOM from 'react-dom';
6 |
7 | ReactDOM.render( , document.getElementById("app"));
--------------------------------------------------------------------------------
/client/src/public/css/main.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Lato');
2 | @import url('https://fonts.googleapis.com/css?family=Roboto+Condensed');
3 | @import url('https://fonts.googleapis.com/css?family=Fira+Sans:200');
4 |
5 | html,
6 | body {
7 | font-family: 'Fira Sans', sans-serif;
8 | background-color: #fafafa;
9 | }
10 |
11 | div {
12 | user-select: none;
13 | -moz-user-select: none;
14 | -khtml-user-select: none;
15 | -webkit-user-select: none;
16 | -o-user-select: none;
17 | }
18 |
19 | .right {
20 | text-align: right;
21 | }
22 |
23 | .left {
24 | text-align: left;
25 | }
26 |
27 | .center {
28 | text-align: center;
29 | }
30 |
31 | .inline {
32 | display: inline-block;
33 | }
34 |
35 | nav .container {
36 | padding-bottom: 0;
37 | padding-top: 0;
38 | }
39 |
40 | nav ul li,
41 | nav h1 {
42 | display: inline;
43 | font-size: 1.4rem;
44 | line-height: 5.2rem;
45 | padding: 0;
46 | text-decoration: none;
47 | }
48 |
49 | nav ul li a .icon {
50 | font-size: 2.2rem;
51 | }
52 |
53 | nav ul li a {
54 | font-family: 'Lato', sans-serif;
55 | }
56 |
57 | nav ul {
58 | float: right;
59 | }
60 |
61 | nav h1 {
62 | font-size: 2rem;
63 | color: #606c76;
64 | position: relative;
65 | }
66 |
67 | nav h1 .colored {
68 | color: #606c76;
69 | transition-duration: 2s;
70 | }
71 |
72 | nav h1:hover .colored {
73 | color: #9b4dca;
74 | }
75 |
76 | nav ul {
77 | list-style: none;
78 | margin-bottom: 0;
79 | margin-right: 5rem;
80 | }
81 |
82 | nav ul li {
83 | float: left;
84 | margin-bottom: 0;
85 | margin-left: 2.5rem;
86 | position: relative;
87 | }
88 |
89 | header {
90 | display: flex;
91 | width: 100%;
92 | align-items: center;
93 | justify-content: center;
94 | position: absolute;
95 | left: 50%;
96 | top: 45%;
97 | transform: translate(-50%, -50%);
98 | }
99 |
100 | header .container {
101 | border-top: 0;
102 | text-align: center;
103 | max-width: 100rem;
104 | width: 50%;
105 | }
106 |
107 | .colored {
108 | color: #9b4dca;
109 | }
110 |
111 | header .endpoint-controls button {
112 | width: 100%;
113 | }
114 |
115 | header h1 {
116 | font-size: 5.6rem;
117 | }
118 |
119 | header .endpoint-controls input {
120 | color: #666;
121 | background-color: white;
122 | }
123 |
124 | footer {
125 | position: absolute;
126 | bottom: 120px;
127 | width: 100%;
128 | text-align: center;
129 | }
130 |
131 | footer .heart,
132 | footer a {
133 | color: #9b4dca;
134 | margin: 0 10px;
135 | }
136 |
137 | .instructions {
138 | color: #666;
139 | font-size: 1.6rem;
140 | padding: 0 30px;
141 | margin-top: 30px;
142 | line-height: 30px;
143 | }
144 |
145 | .instructions h3 {
146 | margin: 0 10px;
147 | color: #606c76;
148 | }
149 |
150 | /* Media queries for responsive behavior on phone */
151 | @media only screen and (max-device-width: 480px) {
152 | #drift-widget-container {
153 | display: none;
154 | }
155 | header .container {
156 | width: 100%;
157 | }
158 |
159 | header h1 {
160 | margin-top: 6rem;
161 | font-size: 3rem;
162 | }
163 |
164 | .endpoint-controls .row .column-60 {
165 | max-width: 100%;
166 | }
167 |
168 | footer {
169 | bottom: 10px;
170 | text-align: center;
171 | }
172 |
173 | nav ul {
174 | margin: 0;
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/client/src/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzi/jsonstore/3da991b7afeaed4342dbc7412287ae44a961c370/client/src/public/favicon.png
--------------------------------------------------------------------------------
/client/src/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jsonstore.io / Store your data just by sending us HTTP Requests
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/client/src/public/js/drift.js:
--------------------------------------------------------------------------------
1 | !function() {
2 | var t;
3 | if (t = window.driftt = window.drift = window.driftt || [], !t.init) return t.invoked ? void (window.console && console.error && console.error("Drift snippet included twice.")) : (t.invoked = !0,
4 | t.methods = [ "identify", "config", "track", "reset", "debug", "show", "ping", "page", "hide", "off", "on" ],
5 | t.factory = function(e) {
6 | return function() {
7 | var n;
8 | return n = Array.prototype.slice.call(arguments), n.unshift(e), t.push(n), t;
9 | };
10 | }, t.methods.forEach(function(e) {
11 | t[e] = t.factory(e);
12 | }), t.load = function(t) {
13 | var e, n, o, i;
14 | e = 3e5, i = Math.ceil(new Date() / e) * e, o = document.createElement("script"),
15 | o.type = "text/javascript", o.async = !0, o.crossorigin = "anonymous", o.src = "https://js.driftt.com/include/" + i + "/" + t + ".js",
16 | n = document.getElementsByTagName("script")[0], n.parentNode.insertBefore(o, n);
17 | });
18 | }();
19 | drift.SNIPPET_VERSION = '0.3.1';
20 | drift.load('mrkxm5g5ducf');
--------------------------------------------------------------------------------
/client/src/services/appService.js:
--------------------------------------------------------------------------------
1 | class AppService {
2 | getToken() {
3 | return fetch('/get-token')
4 | .then(response => response.json())
5 | .then(json => json.token);
6 | }
7 | }
8 |
9 | export default AppService;
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzi/jsonstore/3da991b7afeaed4342dbc7412287ae44a961c370/logo.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "new",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "keywords": [],
7 | "license": "MIT",
8 | "scripts": {
9 | "start": "run-s client:build:dev server:start",
10 | "prod": "PORT=80 npm start",
11 | "server:start": "node ./server",
12 | "client:build:dev": "webpack",
13 | "client:build:prod": "webpack --config webpack.config.prod.js",
14 | "heroku-postbuild": "npm run client:build:prod"
15 | },
16 | "devDependencies": {
17 | "babel-core": "^6.10.4",
18 | "babel-loader": "^7.1.2",
19 | "babel-plugin-transform-class-properties": "^6.24.1",
20 | "babel-plugin-transform-react-jsx": "^6.24.1",
21 | "babel-preset-env": "^1.6.1",
22 | "babel-preset-es2015": "^6.24.1",
23 | "babel-preset-react": "^6.11.1",
24 | "copy-webpack-plugin": "^4.5.1",
25 | "nodemon": "^1.17.2",
26 | "npm-run-all": "^4.1.2",
27 | "webpack": "^3.8.1",
28 | "webpack-node-externals": "^1.2.0"
29 | },
30 | "dependencies": {
31 | "babel-polyfill": "^6.26.0",
32 | "cors": "^2.8.4",
33 | "express": "^4.14.0",
34 | "firebase": "^4.12.1",
35 | "promise-fs": "^1.3.0",
36 | "react": "^16.2.0",
37 | "react-dom": "^16.2.0"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path');
3 | const bodyParser = require('body-parser');
4 | const cors = require('cors');
5 |
6 | const apiRoutes = require('./api/routes');
7 |
8 | const port = process.env.PORT || 3000;
9 | const app = express();
10 |
11 | app.use(express.static(__dirname + '/client/dist'));
12 | app.use(bodyParser.json({
13 | strict: false,
14 | }));
15 | app.use(cors());
16 |
17 | app.get('/', (req, res) => {
18 | res.sendFile(__dirname + '/client/dist/index.html');
19 | });
20 |
21 | app.get('/about', (req, res) => {
22 | res.send('under construction');
23 | });
24 |
25 | app.use(apiRoutes);
26 |
27 | app.use((err, req, res) => {
28 | res.send({
29 | ok: false,
30 | error: 'Unexpected server error',
31 | });
32 | })
33 |
34 | app.listen(port);
35 | console.log(`Serving at http://localhost:${port}`);
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const CopyWebpackPlugin = require('copy-webpack-plugin')
3 |
4 | console.warn('DEVELOPMENT BUILD');
5 |
6 | module.exports = {
7 | entry: ['./client/src/index.js'],
8 | output: {
9 | path: path.resolve(__dirname, './client/dist/'),
10 | filename: 'bundle.js',
11 | },
12 | module: {
13 | loaders: [{
14 | loader: 'babel-loader'
15 | }],
16 | },
17 | plugins: [
18 | new CopyWebpackPlugin([
19 | { from: './client/src/public' },
20 | ])
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/webpack.config.prod.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const CopyWebpackPlugin = require('copy-webpack-plugin')
3 | const webpack = require('webpack')
4 |
5 | console.warn('PRODUCTION BUILD');
6 |
7 | module.exports = {
8 | entry: ['./client/src/index.js'],
9 | output: {
10 | path: path.resolve(__dirname, './client/dist/'),
11 | filename: 'bundle.js',
12 | },
13 | module: {
14 | loaders: [{
15 | loader: 'babel-loader'
16 | }],
17 | },
18 | plugins: [
19 | new CopyWebpackPlugin([
20 | { from: './client/src/public' },
21 | ]),
22 | new webpack.DefinePlugin({
23 | 'process.env.NODE_ENV': JSON.stringify('production')
24 | }),
25 | new webpack.optimize.UglifyJsPlugin()
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------