Setup Meteorjs Server with Ionic 2 CLI

In this tutorial you will learn how to setup a Meteorjs Server with a simple Ionic 2 project using Ionic CLI. As an example, we will call a simple method :).

If you want to directly clone this project, feel free to do this at https://github.com/jayserdny/meteor-ionic

Things to be familiar with before starting this tutorial:

After reading these tutorials, we should be able to start this tutorial :).

First, we will need to create a blank Ionic 2 project. So, in order to create a new Ionic 2 project, you need to run the following command in your terminal:

ionic start meteor-ionic blank --v2

After some minutes, you will have a folder named “meteor-ionic” on the folder you decided to create your application. If not, please try to run again with sudo permission.

Next step is to confirm that the application is already working. So, on the terminal, go to the new folder and run the following command to test your new application:

ionic serve --lab

If everything runs correctly, you will have something like the following image:

Blank Ionic 2 project

Then, in any text editor you prefer (I like Sublime Text) open your project folder and go to the following file /src/pages/home/home.html and you should have the following code in your text editor:

<ion-header>
<ion-navbar>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
The world is your oyster.
<p>
If you get lost, the <a href="http://ionicframework.com/docs/v2">docs</a> will be your guide.
</p>
</ion-content>

Reflect this file with the following code:

<ion-header>
<ion-navbar>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>Server says:</p> {{ serverText }}
</ion-content>

Don’t worry about {{ serverText }}. We will handle this on our home.ts file :)

So, on the same directory, open the home.ts file and reflect the code to the following:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
serverText: string = "Test";
constructor(public navCtrl: NavController) {
}
}

It basically sets the serverText to “Test”. So, in our application you will see the following change:

variable already scoped from home.ts file

So, at this point we already scope the variable from home.ts file. Hence, we are almost ready to install our server for this application :D.

First, we are going to tell Ionic that we are using Webpack as our module-bundler. To do so, add the following field in the package.json file:

... // Lines skipped
"description": "meteor-ionic: An Ionic project",
"config": {
"ionic_webpack": "./webpack.config.js"
}

Now your project know that you want to use Webpack as your module-blundler. Next step is to bring webpack.config.js to our root. It is simple as running the following command:

cp node_modules/@ionic/app-scripts/config/webpack.config.js .

To confirm that it works, go to the root of your project and check if the file “webpack.config.js” exists. If so, you did it correctly :)

Now, open “webpack.config.js” and reflect the following code:

var path = require('path');
var webpack = require('webpack');
var ionicWebpackFactory = require(process.env.IONIC_WEBPACK_FACTORY);
module.exports = {
entry: process.env.IONIC_APP_ENTRY_POINT,
output: {
path: '{{BUILD}}',
publicPath: 'build/',
filename: process.env.IONIC_OUTPUT_JS_FILE_NAME,
devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(),
},
devtool: process.env.IONIC_SOURCE_MAP_TYPE,
resolve: {
extensions: ['.ts', '.js', '.json'],
modules: [path.resolve('node_modules')],
alias: {
'api': path.resolve(__dirname, 'api/server')
}
},

externals: [
resolveExternals
],
module: {
loaders: [
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /\.ts$/,
loader: process.env.IONIC_WEBPACK_LOADER
}
]
},
plugins: [
ionicWebpackFactory.getIonicEnvironmentPlugin(),
new webpack.ProvidePlugin({
__extends: 'typescript-extends'
})
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
fs: 'empty',
net: 'empty',
tls: 'empty',
__dirname: true
}
};
function resolveExternals(context, request, callback) {
return resolveMeteor(request, callback) ||
callback();
}

function resolveMeteor(request, callback) {
var match = request.match(/^meteor\/(.+)$/);
var pack = match && match[1];

if (pack) {
callback(null, 'Package["' + pack + '"]');
return true;
}
}

This basically allow you to load external Typescript modules without any problems, have an alias for our Meteor server under api folder (which we will create later on), and be able to import Meteor packages and Cordova plugins.

Now, open “tsconfig.json” file and reflect the following code:

{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [
"dom",
"es2015"
],
"module": "commonjs",
"moduleResolution": "node",
"paths": {
"api/*": ["./api/server/*"]
},
"sourceMap": true,
"target": "es5",
"skipLibCheck": true,
"stripInternal": true,
"noImplicitAny": false,
"types": [
"meteor-typings",
"@types/underscore"
]
},
"include": [
"src/**/*.ts",
"api/**/*.ts"
],
"exclude": [
"node_modules",
"api/node_modules",
"api"
],
"compileOnSave": false,
"atom": {
"rewriteTsconfig": false
}
}

Now, Typescript knows that we have an api folder that has to be compiled.

Now run the following command to install dependencies needed for Webpack to config correctly our project:

npm install --save-dev typescript-extends
npm install --save-dev @types/underscore
npm install --save-dev meteor-typings

Then, run the project again and if everything worked fine, you should have the following screen again:

Application running without problems after setup project for running the server.

Now we are ready to config our Meteor server :) So, in your root run the following command:

meteor create api

This command will create a new folder on your project root named “api” which will contain files for our server. Next, we will be making some changes to api folder. So, go to this folder on the command line and run the following commands:

rm -rf client
rm package.json
ln -s ../node_modules
meteor add barbatus:typescript
mv server/main.js server/main.ts
ln -s ../src/declarations.d.ts

But wait! What are these commands? Here is a brief explanation:

rm -rf client // This line will remove the client folder from our api folder since Ionic 2 is our client in this case.
rm package.json // Client side already has this file. So, we do not want to have duplicate resources, so delete this file.
ln -s ../node_modules // This one creates a symbolic link between client's node_modules to server.
meteor add barbatus:typescript // Just a package to can use Typescript in our Meteor server.
mv server/main.js server/main.ts // Since we are using Typescript, need to rename from .js to .ts
ln -s ../src/declarations.d.ts // Creates a symbolic link to share declarations between client and server side.

Now you will need to create a tsconfig.json file on api folder root and reflect the following code:

{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [
"dom",
"es2015"
],
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"target": "es5",
"skipLibCheck": true,
"stripInternal": true,
"noImplicitAny": false,
"types": [
"meteor-typings"
]
},
"exclude": [
"node_modules"
],
"compileOnSave": false,
"atom": {
"rewriteTsconfig": false
}
}

Now, move to project root and install the following dependences so our server can run without any problems:

npm install --save babel-runtime
npm install --save meteor-node-stubs
npm install --save meteor-rxjs
npm install --save-dev @types/meteor

In order to connect to the Meteor server, we need a client which is capable of doing so. To create a Meteor client, we will use a bundler called meteor-client-bundler. To do so, run the following command:

sudo npm install -g meteor-client-bundler

If you are using Windows, run a cmd as administrator and run the following command:

npm install -g meteor-client-bundler

After few minutes, open the “package.json” file in project root and reflect the following lines:

... // Some lines skipped
"scripts": {
"clean": "ionic-app-scripts clean",
"build": "ionic-app-scripts build",
"ionic:build": "ionic-app-scripts build",
"ionic:serve": "ionic-app-scripts serve",
"meteor-client:bundle": "meteor-client bundle -s api"

},
... // Some lines skipped
"devDependencies": {
"@ionic/app-scripts": "1.3.7",
"@types/underscore": "^1.8.0",
"meteor-typings": "^1.3.1",
"tmp": "0.0.31",
"typescript": "2.2.1",
"typescript-extends": "^1.0.1"
},

Then, execute the following command to bundle the application:

npm run meteor-client:bundle

This will generate a file called meteor-client.js under the node_modules dir, which needs to be imported in our application. Open src/app/main.ts and add the following line at the top of the file:

import 'meteor-client';

By now, you have your client side connected with your server :)

By default, the client will assume that the server is running at localhost:3000. If you'd like to change that, you can simply specify a --url option in the NPM script. Further information can be found here.

Then, go to api folder and start your server with the following command:

meteor run

After a while, if your application still runs without any errors (ignore the warnings, I will talk about them in other tutorials) your connection was successfully done :).

Now, let start creating a simple Meteor server to later on call it on our client side. So, go to api folder and then go to server folder and create a new folder called “methods”. Go inside methods folder and create a new file named “test.ts”. Then open this file and reflect the following change:

import { Meteor } from 'meteor/meteor';
Meteor.methods({
testMethod: function() {
return "Wassup from server side :)"
},

});

Basically, when we call this method from client side, it should return the text “Wassup from server side :)”. So now, let’s go back to client side and open the following file “src/pages/home/home.ts” and reflect the following code:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Meteor } from 'meteor/meteor';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
serverText: string = "Test";
constructor(public navCtrl: NavController) {

Meteor.call("testMethod", (err, result) => {
if (err) {
console.log(err.reason);
} else {
this.serverText = result;
}
}) ;
}
}

Basically, we are calling the method we created steps ago with a callback. So, if there is an error, the console will log the error, otherwise, serverText will be the result of this call. So, it should set serverText to the text we returned in our method.

If for some reasons you get this error: Cannot find module “meteor/meteor”, create a file named “meteor-client.config.json” on your root and reflect the following code:

{
"run-time": {
"meteorEnv": {},
"DDP_DEFAULT_CONNECTION_URL": "http://localhost:8100"
},
"import": {
"meteor-base@1.0.4": [
"underscore",
"meteor",
"modules-runtime",
"modules",
"promise",
"babel-runtime",
"ecmascript-runtime",
"ecmascript",
"base64",
"ejson",
"jquery",
"check",
"random",
"tracker",
"retry",
"id-map",
"ordered-dict",
"geojson-utils",
"diff-sequence",
"mongo-id",
"minimongo",
"ddp-common",
"ddp-client",
"ddp",
"allow-deny",
"reactive-var",
"mongo"
],
"npm-bcrypt": [],
"accounts-base": [
"callback-hook",
"localstorage",
"accounts-base",
"service-configuration"
],
"mys:accounts-phone": [
"sha",
"srp",
"mys_accounts-phone"
],
"jalik:ufs": [
"observe-sequence",
"htmljs",
"blaze",
"spacebars",
"templating-runtime",
"templating",
"matb33_collection-hooks",
"jalik_ufs"
],
"jalik:ufs-gridfs": [
"jalik_ufs-gridfs"
]
},
"export": {
"accounts-base": ["Accounts"],
"ddp": ["DDP"],
"meteor": ["Meteor"],
"mongo": ["Mongo"],
"tracker": ["Tracker"],
"underscore": ["_"]
}
}

Once your application build again, you will notice the issue is already gone and you should have the following results in your browser:

As you can see, now you are getting the message from server side :)

And finally, we have our Ionic 2 application connected to a Meteor server all using Typescript :D

Please feel free to ask any question and I will love to help you with your questions :).

If you want to directly clone this project, feel free to go to this Github project: https://github.com/jayserdny/meteor-ionic

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.