Difference between revisions of "User:Saul/Realtime app"

From Organic Design wiki
(Setup: Subdivided and adding lost more info.)
m (feathers)
 
(39 intermediate revisions by the same user not shown)
Line 1: Line 1:
This is the documentation for the stack I use for creating a real-time application. The stack consists of node.js and feathers.js for the server, the client uses: Vue, vue-router, vuex and setup using the vue webpack.
+
This is the documentation for the stack I use for creating a real-time application. You can find the repository to download a simple general boilerplate [https://github.com/saul-avikar/feathers-vue-boilerplate here].  The stack consists of node.js and feathers.js for the server, the client uses: Vue, vue-router, vuex and setup using the vue webpack.
 +
The repository for the boilerplate with this stack can be found here: [http://github.com/nutmmm/vue-boilerplate vue-boilerplate]
  
== Setup ==
+
= Setup =
=== Install And Generate Files ===
+
== Install Cli Libs ==
 +
This globally installs the feathers and vue cli's onto the system so if you have already done this before you can skip this step.
 +
=== vue ===
 +
<source lang="bash">
 +
sudo npm install -g vue
 +
</source>
 +
=== feathers ===
 +
<source lang="bash">
 +
sudo npm i -g @feathersjs/cli
 +
</source>
 +
 
 +
== Generate Files ==
 
The following commands will setup the app:
 
The following commands will setup the app:
 
<source lang="bash">
 
<source lang="bash">
sudo npm install -g vue @feathersjs/cli # install dependencies globally
+
mkdir APPNAME APPNAME/server APPNAME/client && cd APPNAME # prepare file structure
 
sudo vue init webpack-simple APPNAME # create a new project using the "webpack-simple" template
 
sudo vue init webpack-simple APPNAME # create a new project using the "webpack-simple" template
mkdir APPNAME/server && cd APPNAME/server
+
cd server
 
feathers generate app # generate the feathers app
 
feathers generate app # generate the feathers app
 
</source>
 
</source>
  
=== Modify Files ===
+
== Modify Files ==
 
A few changes are need to finish connecting the app:<br>
 
A few changes are need to finish connecting the app:<br>
 
<br>
 
<br>
Copy all dependencies from server/package.json to the package.json located in the root dir. Do the same for request and request-promise from devDependencies.<br>
+
Copy all dependencies from <b>server/package.json</b> to the <b>package.json</b> located in the root dir. Do the same for request and request-promise from devDependencies.<br>
Add to the scripts section in package.json (this allows the back end to be started via "npm run server"):
+
<br>
 +
Add to the scripts section in <b>package.json</b> (this allows the back end to be started via "npm run server"):
 
<source lang="json">
 
<source lang="json">
 
"server": "node server/src/",
 
"server": "node server/src/",
 
</source>
 
</source>
Add to package.json:
+
Add to <b>package.json</b>:
 
<source lang="json">
 
<source lang="json">
 
"directories": {
 
"directories": {
Line 25: Line 38:
 
},
 
},
 
</source>
 
</source>
Modify the dev script in package.json to:
+
Modify the dev script in <b>package.json</b> to:
 
<source lang="json">
 
<source lang="json">
 
"cross-env NODE_ENV=development webpack-dev-server --content-base server/public --open --hot"
 
"cross-env NODE_ENV=development webpack-dev-server --content-base server/public --open --hot"
 
</source>
 
</source>
Modify the config/default.json file like so:
+
Modify the <b>config/default.json</b> file like so:
 
<source lang="json">
 
<source lang="json">
 
"public": "../server/public/",
 
"public": "../server/public/",
 
</source>
 
</source>
Modify the webpack.config.js by changing the path and publicPath like so:
+
Modify the <b>webpack.config.js</b> by changing the path and publicPath like so:
 
<source lang="json">
 
<source lang="json">
 
path: path.resolve(__dirname, "server", "public"),
 
path: path.resolve(__dirname, "server", "public"),
 
publicPath: "/",
 
publicPath: "/",
 
</source>
 
</source>
Modify the index.html so that the script build source is:
+
Remove the line in <b>webpack.config.js</b> which makes babel-loader exclude the node module folders.<br>
 +
This appears to make build crash for some reason, perhaps feathers.js is written in es6, when it should be written in es5?
 +
<source lang="js">
 +
// modify this section like so:
 +
test: /\.js$/,
 +
loader: 'babel-loader'/*,
 +
exclude: /node_modules/*/
 +
</source>
 +
Modify the <b>index.html</b> so that the script build source is:
 
<source lang="html">
 
<source lang="html">
<script src="build.js"></script>
+
<script src="/build.js"></script>
 
</source>
 
</source>
  
=== Fix Structure, Install, And Cleanup ===
+
== Fix Structure, Install, And Cleanup ==
 
These commands will finish arranging the files (make sure you are still in the server dir):
 
These commands will finish arranging the files (make sure you are still in the server dir):
 
<source lang="bash">
 
<source lang="bash">
Line 52: Line 73:
 
<source lang="bash">
 
<source lang="bash">
 
cd .. # go back to the project root
 
cd .. # go back to the project root
npm i @feathersjs/client vuex # install additional dependencies (socket.io-client may also be needed?)
+
npm i @feathersjs/client vuex vue-router # install additional dependencies
 
npm i # install dependencies
 
npm i # install dependencies
 
</source>
 
</source>
=== Run App ===
+
 
 +
== Run App ==
 
To run in development:
 
To run in development:
 
<source lang="bash">
 
<source lang="bash">
Line 66: Line 88:
 
npm run server # run the backend
 
npm run server # run the backend
 
</source>
 
</source>
=== See Also ===
+
== See Also ==
 
*[[User:Saul/linode#Setting_Up_Node.js]]
 
*[[User:Saul/linode#Setting_Up_Node.js]]
 +
 +
= Client  =
 +
== File Structure ==
 +
To generate the recommended file structure, navigate to the project root directory and run the following command:
 +
<source lang="bash">
 +
mkdir src/components src/store src/libs src/pages # generate the client end folders: components (for storing vue components), store (for storing vuex store files), and libs (for storing client side js libs)
 +
</source>
 +
=== Auto ===
 +
To automatically edit the files run this one-liner or skip to [[User:Saul/Realtime_app#Manual|manual]] if you would like to manually edit them.
 +
The code does the following:
 +
*generates the src/store/index.js file with an example included.
 +
*generates the src/router.js file with examples
 +
*generates the src/libs/conf.js to use the configuration settings
 +
*generates the src/libs/client.js to setup feathers with socket.io
 +
*rewrites App.vue to use the vue-router
 +
*rewrites main.js to use the vue-router and vuex
 +
<source lang="bash">
 +
echo -e "import Vue from \"vue\"\nimport Vuex from \"vuex\"\n//import chat from \"./SOTRENAMEONE\"\n//import login from \"./SOTRENAMETWO\"\n\nVue.use(Vuex)\n\nexport default new Vuex.Store({\n\tmodules: {\n\t\t/*\n\t\t\tchat,\n\t\t\tlogin\n\t\t*/\n\t}\n})" > src/store/index.js && echo -e "import Vue from \"vue\"\nimport Router from \"vue-router\"\n//import Login from \"./pages/Login.vue\"\n//import Register from \"./pages/Register.vue\"\n//import Chat from \"./pages/Chat.vue\"\n//import auth from \"./libs/auth\"\n\nVue.use(Router)\n\nconst router = new Router({\n\tmode: \"history\",\n\troutes: [\n\t\t/*\n\t\t\t{\n\t\t\t\tpath: \"/\",\n\t\t\t\tname: \"Chat\",\n\t\t\t\tcomponent: Chat,\n\t\t\t\tbeforeEnter: auth.isLoggedIn\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: \"/login\",\n\t\t\t\tname: \"Login\",\n\t\t\t\tcomponent: Login\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: \"/register\",\n\t\t\t\tname: \"Register\",\n\t\t\t\tcomponent: Register\n\t\t\t},\n\t\t*/\n\t\t// If access a non-existing route, redirect to root route\n\t\t{\n\t\t\tpath: \"*\",\n\t\t\tredirect: \"/\"\n\t\t}\n\t]\n})\n\nrouter.afterEach(function (to, from){\n\t//Set the title for the pages\n\tdocument.title = to.name;\n});\n\nexport default router;" > src/router.js && echo -e "<template>\n\t<div id=\"app\">\n\t\t<router-view></router-view>\n\t</div>\n</template>\n\n<script>\n\texport default {\n\t\tname: \"app\"\n\t}\n</script>\n\n<style>\n\t#app, body, html{\n\t\tbox-sizing: border-box;\n\t\tpadding: 0px;\n\t\tmargin: 0px;\n\t}\n</style>" > src/App.vue && echo -e "import Vue from \"vue\"\nimport App from \"./App.vue\"\nimport router from \"./router\"\nimport store from \"./store\"\n\nnew Vue({\n\tel: \"#app\",\n\tstore,\n\trouter,\n\trender: h => h(App)\n})" > src/main.js && echo -e "import defaultConf from \"../../config/default.json\"\nimport productionConf from \"../../config/production.json\"\nimport merge from \"lodash.merge\"\n\nlet conf = merge({}, defaultConf)\n\n// When we build for production, merge production conf\nif (process.env.NODE_ENV === \"production\") {\n\tconf = merge(conf, productionConf)\n}\n\nexport default conf" > src/libs/conf.js && echo -e "import io from \"socket.io-client\";\nimport feathers from \"@feathersjs/feathers\";\nimport socketio from \"@feathersjs/socketio-client\";\nimport auth from \"@feathersjs/authentication-client\";\n\nimport conf from \"./conf\";\n\nconst client = feathers();\n\nconst socket = io(\`http://\${conf.host}:\${conf.port}\`, {\n\ttransports: [\"websocket\"],\n\tforceNew: true\n});\n\nclient.configure(auth({ storage: localStorage }));\n// Create the Feathers application with a \`socketio\` connection\nclient.configure(socketio(socket));\n\nexport default client;" > src/libs/client.js
 +
</source>
 +
 +
=== Manual ===
 +
This section does the same thing manually as [[User:Saul/Realtime_app#Auto|Auto]] does.<br>
 +
<br>
 +
First create the src/store/index.js file like this:
 +
<source lang="javascript">
 +
import Vue from "vue"
 +
import Vuex from "vuex"
 +
//import chat from "./SOTRENAMEONE"
 +
//import login from "./SOTRENAMETWO"
 +
 +
Vue.use(Vuex)
 +
 +
export default new Vuex.Store({
 +
modules: {
 +
/*
 +
chat,
 +
login
 +
*/
 +
}
 +
})
 +
</source>
 +
Then create the src/router.js file with the following:
 +
<source lang="javascript">
 +
import Vue from "vue"
 +
import Router from "vue-router"
 +
//import Login from "./pages/Login.vue"
 +
//import Register from "./pages/Register.vue"
 +
//import Chat from "./pages/Chat.vue"
 +
//import auth from "./libs/auth"
 +
 +
Vue.use(Router)
 +
 +
const router = new Router({
 +
mode: "history",
 +
routes: [
 +
/*
 +
{
 +
path: "/",
 +
name: "Chat",
 +
component: Chat,
 +
beforeEnter: auth.isLoggedIn
 +
},
 +
{
 +
path: "/login",
 +
name: "Login",
 +
component: Login
 +
},
 +
{
 +
path: "/register",
 +
name: "Register",
 +
component: Register
 +
},
 +
*/
 +
// If access a non-existing route, redirect to root route
 +
{
 +
path: "*",
 +
redirect: "/"
 +
}
 +
]
 +
})
 +
 +
router.afterEach(function (to, from){
 +
//Set the title for the pages
 +
document.title = to.name;
 +
});
 +
 +
export default router;
 +
</source>
 +
Then change the contents of App.vue like so:
 +
<source lang="html">
 +
<template>
 +
<div id="app">
 +
<router-view></router-view>
 +
</div>
 +
</template>
 +
 +
<script>
 +
export default {
 +
name: "app"
 +
}
 +
</script>
 +
 +
<style>
 +
#app, body, html{
 +
box-sizing: border-box;
 +
padding: 0px;
 +
margin: 0px;
 +
}
 +
</style>
 +
</source>
 +
Change the contents main.js to use the vue-router and vuex like this:
 +
<source lang="javascript">
 +
import Vue from "vue"
 +
import App from "./App.vue"
 +
import router from "./router"
 +
import store from "./store"
 +
 +
new Vue({
 +
el: "#app",
 +
store,
 +
router,
 +
render: h => h(App)
 +
})
 +
</source>
 +
 +
Create the client conf data lib as src/libs/conf.js:
 +
<source lang="javascript">
 +
import defaultConf from "../../config/default.json"
 +
import productionConf from "../../config/production.json"
 +
import merge from "lodash.merge"
 +
 +
let conf = merge({}, defaultConf)
 +
 +
// When we build for production, merge production conf
 +
if (process.env.NODE_ENV === "production") {
 +
  conf = merge(conf, productionConf)
 +
}
 +
 +
export default conf
 +
</source>
 +
 +
Finally create the feathers lib as src/libs/client.js:
 +
<source lang="javascript">
 +
import io from "socket.io-client";
 +
import feathers from "@feathersjs/feathers";
 +
import socketio from "@feathersjs/socketio-client";
 +
import auth from "@feathersjs/authentication-client";
 +
 +
import conf from "./conf";
 +
 +
const client = feathers();
 +
 +
const socket = io(`http://${conf.host}:${conf.port}`, {
 +
transports: ["websocket"],
 +
forceNew: true
 +
});
 +
 +
client.configure(auth({ storage: localStorage }));
 +
// Create the Feathers application with a `socketio` connection
 +
client.configure(socketio(socket));
 +
 +
export default client;
 +
</source>
 +
 +
== Creating Pages ==
 +
For every page you would like to make create a file in src/pages/PAGENAME.vue and then add it in the src/router.js file.<br>
 +
Each page should have the standard vue template:
 +
<source lang="html">
 +
<template>
 +
</template>
 +
 +
<script>
 +
</script>
 +
 +
<style>
 +
</style>
 +
</source>
 +
 +
== Creating Components ==
 +
Components are independent pieces of code to be embedded into a page.<br>
 +
For every component you would like to make create a file in src/component/COMPONENTNAME.vue<br>
 +
Each component should have the standard vue template (like pages do).<br>
 +
To embed the components in a page you need to import them in the page (in the script section):
 +
<source lang="javascript">
 +
import Chat from './components/chat.vue'
 +
import Channels from './components/channels.vue'
 +
 +
export default{
 +
components: {
 +
Channels,
 +
Chat
 +
}
 +
}
 +
</source>
 +
Then you can use them in the template section like so:
 +
<source lang="html">
 +
<channels></channels>
 +
<chat></chat>
 +
</source>
 +
 +
== Creating Vuex Stores ==
 +
Vuex stores are ways of preserving state.<br>
 +
To create a vuex store for your application create the <b>folder</b> src/store/STORENAME<br>
 +
Create a index.js file in the src/store/STORENAME folder.
 +
The index.js file should contain something like:
 +
<source lang="javascript">
 +
export const state = {
 +
// This should contain variables that you would like to preserve
 +
}
 +
 +
export const mutations = {
 +
// This should contain methods for modifying the state section but should not be called directly
 +
}
 +
 +
export const actions = {
 +
// This should contain methods that do not modify the state directly
 +
// They may however modify the stat by calling a method in the mutations
 +
// This may be done via: commit("mutation_name", channel)
 +
}
 +
 +
export const getters = {
 +
// This should contain methods for retrieving the data from the state
 +
}
 +
 +
export default {
 +
  state,
 +
  mutations,
 +
  actions,
 +
  getters
 +
}
 +
</source>
 +
Then you need to modify the src/store/index.js to reference it.<br>
 +
Then you can import it into your pages and use the data.
 +
 +
== Using JS Librarys ==
 +
To add a JS library just create the file src/libs/LIBNAME.js<br>
 +
Add the code into that file and import it into the relevant files.<br>
 +
You may like to add an auth.js file to handle authentication and loggin in and out.<br>
 +
Another file that you probably will need is a services file for handling the service calls to the server eg. creating a message.
 +
 +
== Listening To Server events ==
 +
The server by default will publish all events to all authenticated users by adding them to the "authenticated" channel and publishing all events across that channel.<br>
 +
So to listen to an event eg. when a message is created, make sure to import the client and create the listener like so:
 +
<source lang="javascript">
 +
import client from '../libs/client'
 +
 +
export default {
 +
created(){
 +
client.service("messages").on("created", message => {
 +
// Do something
 +
});
 +
}
 +
}
 +
</source>
 +
 +
= Server =
 +
== Routing ==
 +
Some modifications need to be made so the server understands how to deliver content.<br>
 +
If you try to go to localhost:3030/somepagename you will get a 404 error.<br>
 +
So to fix this add below the public folder host route the following code:
 +
<source lang="javascript">
 +
// This line already exists:
 +
app.use('/', express.static(app.get('public')));
 +
// Add these 3 lines:
 +
app.get('/*',  function(req,res){
 +
res.sendFile(path.join(app.get('public'), 'index.html'));
 +
});
 +
</source>
 +
This will make all routes return the index.html file but keep the route for vue to handle.
 +
== Services ==
 +
Services are used as a system of communication between the client server and database.<br>
 +
Services set most of the code automatically so you won't need to do much<br>
 +
To generate a feathers js service run:
 +
<source lang="bash">
 +
feathers generate service # Creates the feathers.js service
 +
# Example: Mongoose, messages, /messages, mongodb://localhost:27017/chat
 +
</source>
 +
If you have issues with a service check what the service name is.<br>
 +
Most of what will need editing is in the service's hooks.js file, and and the corresponding model file.<br>
 +
The model file may need changing to add or remove fields to require the data you want the database to store.<br>
 +
The hooks file may need some hook functions created to modify data eg. change the date and times into human readable format<br>
 +
To generate the authentication service run:
 +
<source lang="bash">
 +
feathers generate authentication # Creates the feathers.js authentication service
 +
</source>
 +
Authentication automatically creates the necessary hooks for protecting users passwords.<br>
 +
The authentication will also create the channels.js which sets up publishing for channels.

Latest revision as of 00:44, 2 July 2018

This is the documentation for the stack I use for creating a real-time application. You can find the repository to download a simple general boilerplate here. The stack consists of node.js and feathers.js for the server, the client uses: Vue, vue-router, vuex and setup using the vue webpack. The repository for the boilerplate with this stack can be found here: vue-boilerplate

Setup

Install Cli Libs

This globally installs the feathers and vue cli's onto the system so if you have already done this before you can skip this step.

vue

sudo npm install -g vue

feathers

sudo npm i -g @feathersjs/cli

Generate Files

The following commands will setup the app:

mkdir APPNAME APPNAME/server APPNAME/client && cd APPNAME # prepare file structure
sudo vue init webpack-simple APPNAME # create a new project using the "webpack-simple" template
cd server
feathers generate app # generate the feathers app

Modify Files

A few changes are need to finish connecting the app:

Copy all dependencies from server/package.json to the package.json located in the root dir. Do the same for request and request-promise from devDependencies.

Add to the scripts section in package.json (this allows the back end to be started via "npm run server"):

"server": "node server/src/",

Add to package.json:

"directories": {
	"lib": "server/src"
},

Modify the dev script in package.json to:

"cross-env NODE_ENV=development webpack-dev-server --content-base server/public --open --hot"

Modify the config/default.json file like so:

"public": "../server/public/",

Modify the webpack.config.js by changing the path and publicPath like so:

path: path.resolve(__dirname, "server", "public"),
publicPath: "/",

Remove the line in webpack.config.js which makes babel-loader exclude the node module folders.
This appears to make build crash for some reason, perhaps feathers.js is written in es6, when it should be written in es5?

// modify this section like so:
test: /\.js$/,
loader: 'babel-loader'/*,
exclude: /node_modules/*/

Modify the index.html so that the script build source is:

<script src="/build.js"></script>

Fix Structure, Install, And Cleanup

These commands will finish arranging the files (make sure you are still in the server dir):

mv config ../config && mv .editorconfig ../.editorconfig && mv ../index.html public/index.html # move then files to the proper dirs
rm package.json LICENSE .gitignore .npmignore README.md .eslintrc.json package-lock.json -R test node_modules # delete the unnecessary files

And to install the dependencies and run:

cd .. # go back to the project root
npm i @feathersjs/client vuex vue-router # install additional dependencies
npm i # install dependencies

Run App

To run in development:

npm run dev # this launches the front-end
npm run server # this launches the back-end

To run in production:

npm build # build the front-end into the backend
npm run server # run the backend

See Also

Client

File Structure

To generate the recommended file structure, navigate to the project root directory and run the following command:

mkdir src/components src/store src/libs src/pages # generate the client end folders: components (for storing vue components), store (for storing vuex store files), and libs (for storing client side js libs)

Auto

To automatically edit the files run this one-liner or skip to manual if you would like to manually edit them. The code does the following:

  • generates the src/store/index.js file with an example included.
  • generates the src/router.js file with examples
  • generates the src/libs/conf.js to use the configuration settings
  • generates the src/libs/client.js to setup feathers with socket.io
  • rewrites App.vue to use the vue-router
  • rewrites main.js to use the vue-router and vuex
echo -e "import Vue from \"vue\"\nimport Vuex from \"vuex\"\n//import chat from \"./SOTRENAMEONE\"\n//import login from \"./SOTRENAMETWO\"\n\nVue.use(Vuex)\n\nexport default new Vuex.Store({\n\tmodules: {\n\t\t/*\n\t\t\tchat,\n\t\t\tlogin\n\t\t*/\n\t}\n})" > src/store/index.js && echo -e "import Vue from \"vue\"\nimport Router from \"vue-router\"\n//import Login from \"./pages/Login.vue\"\n//import Register from \"./pages/Register.vue\"\n//import Chat from \"./pages/Chat.vue\"\n//import auth from \"./libs/auth\"\n\nVue.use(Router)\n\nconst router = new Router({\n\tmode: \"history\",\n\troutes: [\n\t\t/*\n\t\t\t{\n\t\t\t\tpath: \"/\",\n\t\t\t\tname: \"Chat\",\n\t\t\t\tcomponent: Chat,\n\t\t\t\tbeforeEnter: auth.isLoggedIn\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: \"/login\",\n\t\t\t\tname: \"Login\",\n\t\t\t\tcomponent: Login\n\t\t\t},\n\t\t\t{\n\t\t\t\tpath: \"/register\",\n\t\t\t\tname: \"Register\",\n\t\t\t\tcomponent: Register\n\t\t\t},\n\t\t*/\n\t\t// If access a non-existing route, redirect to root route\n\t\t{\n\t\t\tpath: \"*\",\n\t\t\tredirect: \"/\"\n\t\t}\n\t]\n})\n\nrouter.afterEach(function (to, from){\n\t//Set the title for the pages\n\tdocument.title = to.name;\n});\n\nexport default router;" > src/router.js && echo -e "<template>\n\t<div id=\"app\">\n\t\t<router-view></router-view>\n\t</div>\n</template>\n\n<script>\n\texport default {\n\t\tname: \"app\"\n\t}\n</script>\n\n<style>\n\t#app, body, html{\n\t\tbox-sizing: border-box;\n\t\tpadding: 0px;\n\t\tmargin: 0px;\n\t}\n</style>" > src/App.vue && echo -e "import Vue from \"vue\"\nimport App from \"./App.vue\"\nimport router from \"./router\"\nimport store from \"./store\"\n\nnew Vue({\n\tel: \"#app\",\n\tstore,\n\trouter,\n\trender: h => h(App)\n})" > src/main.js && echo -e "import defaultConf from \"../../config/default.json\"\nimport productionConf from \"../../config/production.json\"\nimport merge from \"lodash.merge\"\n\nlet conf = merge({}, defaultConf)\n\n// When we build for production, merge production conf\nif (process.env.NODE_ENV === \"production\") {\n\tconf = merge(conf, productionConf)\n}\n\nexport default conf" > src/libs/conf.js && echo -e "import io from \"socket.io-client\";\nimport feathers from \"@feathersjs/feathers\";\nimport socketio from \"@feathersjs/socketio-client\";\nimport auth from \"@feathersjs/authentication-client\";\n\nimport conf from \"./conf\";\n\nconst client = feathers();\n\nconst socket = io(\`http://\${conf.host}:\${conf.port}\`, {\n\ttransports: [\"websocket\"],\n\tforceNew: true\n});\n\nclient.configure(auth({ storage: localStorage }));\n// Create the Feathers application with a \`socketio\` connection\nclient.configure(socketio(socket));\n\nexport default client;" > src/libs/client.js

Manual

This section does the same thing manually as Auto does.

First create the src/store/index.js file like this:

import Vue from "vue"
import Vuex from "vuex"
//import chat from "./SOTRENAMEONE"
//import login from "./SOTRENAMETWO"

Vue.use(Vuex)

export default new Vuex.Store({
	modules: {
		/*
			chat,
			login
		*/
	}
})

Then create the src/router.js file with the following:

import Vue from "vue"
import Router from "vue-router"
//import Login from "./pages/Login.vue"
//import Register from "./pages/Register.vue"
//import Chat from "./pages/Chat.vue"
//import auth from "./libs/auth"

Vue.use(Router)

const router = new Router({
	mode: "history",
	routes: [
		/*
			{
				path: "/",
				name: "Chat",
				component: Chat,
				beforeEnter: auth.isLoggedIn
			},
			{
				path: "/login",
				name: "Login",
				component: Login
			},
			{
				path: "/register",
				name: "Register",
				component: Register
			},
		*/
		// If access a non-existing route, redirect to root route
		{
			path: "*",
			redirect: "/"
		}
	]
})

router.afterEach(function (to, from){
	//Set the title for the pages
	document.title = to.name;
});

export default router;

Then change the contents of App.vue like so:

<template>
	<div id="app">
		<router-view></router-view>
	</div>
</template>

<script>
	export default {
		name: "app"
	}
</script>

<style>
	#app, body, html{
		box-sizing: border-box;
		padding: 0px;
		margin: 0px;
	}
</style>

Change the contents main.js to use the vue-router and vuex like this:

import Vue from "vue"
import App from "./App.vue"
import router from "./router"
import store from "./store"

new Vue({
	el: "#app",
	store,
	router,
	render: h => h(App)
})

Create the client conf data lib as src/libs/conf.js:

import defaultConf from "../../config/default.json"
import productionConf from "../../config/production.json"
import merge from "lodash.merge"

let conf = merge({}, defaultConf)

// When we build for production, merge production conf
if (process.env.NODE_ENV === "production") {
  conf = merge(conf, productionConf)
}

export default conf

Finally create the feathers lib as src/libs/client.js:

import io from "socket.io-client";
import feathers from "@feathersjs/feathers";
import socketio from "@feathersjs/socketio-client";
import auth from "@feathersjs/authentication-client";

import conf from "./conf";

const client = feathers();

const socket = io(`http://${conf.host}:${conf.port}`, {
	transports: ["websocket"],
	forceNew: true
});

client.configure(auth({ storage: localStorage }));
// Create the Feathers application with a `socketio` connection
client.configure(socketio(socket));

export default client;

Creating Pages

For every page you would like to make create a file in src/pages/PAGENAME.vue and then add it in the src/router.js file.
Each page should have the standard vue template:

<template>
</template>

<script>
</script>

<style>
</style>

Creating Components

Components are independent pieces of code to be embedded into a page.
For every component you would like to make create a file in src/component/COMPONENTNAME.vue
Each component should have the standard vue template (like pages do).
To embed the components in a page you need to import them in the page (in the script section):

import Chat from './components/chat.vue'
import Channels from './components/channels.vue'

export default{
	components: {
		Channels,
		Chat
	}
}

Then you can use them in the template section like so:

<channels></channels>
<chat></chat>

Creating Vuex Stores

Vuex stores are ways of preserving state.
To create a vuex store for your application create the folder src/store/STORENAME
Create a index.js file in the src/store/STORENAME folder. The index.js file should contain something like:

export const state = {
	// This should contain variables that you would like to preserve
}

export const mutations = {
	// This should contain methods for modifying the state section but should not be called directly
}

export const actions = {
	// This should contain methods that do not modify the state directly
	// They may however modify the stat by calling a method in the mutations
	// This may be done via: commit("mutation_name", channel)
}

export const getters = {
	// This should contain methods for retrieving the data from the state
}

export default {
  state,
  mutations,
  actions,
  getters
}

Then you need to modify the src/store/index.js to reference it.
Then you can import it into your pages and use the data.

Using JS Librarys

To add a JS library just create the file src/libs/LIBNAME.js
Add the code into that file and import it into the relevant files.
You may like to add an auth.js file to handle authentication and loggin in and out.
Another file that you probably will need is a services file for handling the service calls to the server eg. creating a message.

Listening To Server events

The server by default will publish all events to all authenticated users by adding them to the "authenticated" channel and publishing all events across that channel.
So to listen to an event eg. when a message is created, make sure to import the client and create the listener like so:

import client from '../libs/client'

export default {
	created(){
		client.service("messages").on("created", message => {
			// Do something
		});
	}
}

Server

Routing

Some modifications need to be made so the server understands how to deliver content.
If you try to go to localhost:3030/somepagename you will get a 404 error.
So to fix this add below the public folder host route the following code:

// This line already exists:
app.use('/', express.static(app.get('public')));
// Add these 3 lines:
app.get('/*',  function(req,res){
	res.sendFile(path.join(app.get('public'), 'index.html'));
});

This will make all routes return the index.html file but keep the route for vue to handle.

Services

Services are used as a system of communication between the client server and database.
Services set most of the code automatically so you won't need to do much
To generate a feathers js service run:

feathers generate service # Creates the feathers.js service
# Example: Mongoose, messages, /messages, mongodb://localhost:27017/chat

If you have issues with a service check what the service name is.
Most of what will need editing is in the service's hooks.js file, and and the corresponding model file.
The model file may need changing to add or remove fields to require the data you want the database to store.
The hooks file may need some hook functions created to modify data eg. change the date and times into human readable format
To generate the authentication service run:

feathers generate authentication # Creates the feathers.js authentication service

Authentication automatically creates the necessary hooks for protecting users passwords.
The authentication will also create the channels.js which sets up publishing for channels.