office-js + outlook-web-addins + Webpack + Production - node.js

I am totally new to NodeJS, Webpack and specially to Outlook Addin. So, I created my Outlook Addin using basic tutorials from https://learn.microsoft.com/en-us/outlook/add-ins/addin-tutorial, all went well.
However, when it came to deployment on Production, I struggled a lot. I put all my code up on Production (Ubuntu instance). First tested a simple NodeJS "hello World" app on Port:8080 and it worked just fine. Then I tried to start my Outlook Addin, just like I was doing locally, it started on port 3000, but I needed to run it on 8080 and in the background. So, I used "PM2", and here comes the "WALL".
pm2 start src/index.js doesn't work for me, as the inside Office.onReady or any other reference to Office does not work, throws undefined Office error.
I tried pm2 run-script build, (after modifications in package.json and webpack.prod.js files)
However, I am still getting the same error when try to run pm2 start dist/app.bundle.js
So, please guide me which file should I reference to when using pm2 start {filename/path}?
Here are some configurations that I am using,
webpack.common.js
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
polyfill: 'babel-polyfill',
app: './src/index.js',
'function-file': './function-file/function-file.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.html$/,
exclude: /node_modules/,
use: 'html-loader'
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: 'file-loader'
}
]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Production'
}),
new HtmlWebpackPlugin({
template: './index.html',
chunks: ['polyfill', 'app']
}),
new HtmlWebpackPlugin({
template: './function-file/function-file.html',
filename: 'function-file/function-file.html',
chunks: ['function-file']
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
webpack.prod.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map'
});

Contents of an Add-in
The files that are produced from your project when building should be at least some JavaScript, then perhaps HTML and some CSS, depending on what kind of add-in you're building. The most common is probably building an add-in with a task pane - which is basically a web page. In any case, the built files is not a Node.js web server.
Hosting your Add-in
Making your add-in available inside Outlook or Office requires that you host your files somewhere. It can be done with any web server - a simple python web server, Apache, Node.js HTTP server, or anything similar. It can be done on either localhost or in some other hosting service. The add-in tutorial shows you how to run a Webpack development server to host the files on https://localhost:3000 while you are coding (npm run start).
In your manifest.xml file you'll notice that you specify the address where your files are hosted. In my development setup, for an add-in with a task pane, I've specified that the files are hosted on localhost, like this:
<FormSettings>
<Form xsi:type="ItemRead">
<DesktopSettings>
<SourceLocation DefaultValue="https://localhost:3000/index.html"/>
<RequestedHeight>250</RequestedHeight>
</DesktopSettings>
</Form>
</FormSettings>
Production
However, when running your app in production, the tutorial says that you should do npm run build. Those files that are produced, need to be hosted somewhere. I've hosted my add-in on Amazon S3, which is another way of hosting files.
To simulate it on localhost, follow these steps.
In the same folder as your project (where the dist/ folder is located):
Run npm install http-server -g
Run http-server dist/
Tools
To clarify what the tools are used for:
Webpack is what puts your app together, from your source code to a bundled version which can be run in a browser context. Webpack development server can be used to host files on localhost during development
Node.js HTTP server can also be used to host files on your localhost
pm2 is a process manager for Node.js. You can use it for hosting a Node.js server in production

#shahroon and I working on the issue together. We're still not able to get things to work and have now paid for a support with Microsoft. Sadly and very frustratingly Microsoft hasn't even acknowledge our support ticket and it's been 3 days.

Related

How to bundle node module CSS into a vscode extension

My Visual Studio Code extension uses the node module highlight.js which comes with a folder full of CSS files. These provide colour schemes for syntax colouring. It has become necessary to bundle some of the CSS files.
It's about bundling an asset
The objective is to bundle a CSS file and at run-time access the file content as a string. If that can be achieved without an import statement that would be perfect. Normally, how exactly one accesses the content of the bundled file would be a separate question, but I have a feeling that content retrieval and how one should go about bundling the asset are closely entwined.
I freely admit to having a weak understanding of WebPack.
The story so far
The bundler is specified in package.json as "webpack": "^5.4.0" but I don't know how to ascertain what is actually present. It is conceivable that there is something wrong with my setup: when I try to run webpack --version on a command prompt in the project folder, it responds
CLI for webpack must be installed.
webpack-cli (https://github.com/webpack/webpack-cli)
We will use "npm" to install the CLI via "npm install -D webpack-cli".
Do you want to install 'webpack-cli' (yes/no):
The first time this happened I responded yes. After a flurry of installation and another try the same thing happened. However, vsce package has no trouble using webpack for a production build and pressing F5 to debug successfully puts together a development build in a dist folder with an unminified file I can examine (which is how I know the file mentioned below is being bundled).
Moving on from there I've modified webpack.config.js like so
//#ts-check
'use strict';
const path = require('path');
/**#type {import('webpack').Configuration}*/
const config = {
target: 'node', // vscode extensions run in a Node.js-context -> https://webpack.js.org/configuration/node/
entry: './src/extension.ts', // the entry point of this extension, -> https://webpack.js.org/configuration/entry-context/
output: {
// the bundle is stored in the 'dist' folder (check package.json), -> https://webpack.js.org/configuration/output/
path: path.resolve(__dirname, 'dist'),
filename: 'extension.js',
libraryTarget: 'commonjs2',
devtoolModuleFilenameTemplate: '../[resource-path]'
},
devtool: 'source-map',
externals: {
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, -> https://webpack.js.org/configuration/externals/
},
resolve: {
// support reading TypeScript and JavaScript files, -> https://github.com/TypeStrong/ts-loader
extensions: ['.ts', '.js', '.css']
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
};
module.exports = config;
As you can see there are rules and loaders for CSS.
When I add this import
import "../node_modules/highlight.js/styles/atelier-dune-light.css";
webpack happily builds the bundle and when I inspect it I can find the bundled CSS.
However, when I try to load the extension in the extension debug host, it fails to load, with this message.
Activating extension 'pdconsec.vscode-print' failed: document is not defined.
Enabling break on caught exceptions reveals this rather surprising exception.
Exception has occurred: Error: Cannot find module 'supports-color'
Require stack:
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\get-uri\node_modules\debug\src\node.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\get-uri\node_modules\debug\src\index.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\get-uri\dist\index.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\vscode-proxy-agent\out\agent.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\vscode-proxy-agent\out\index.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\out\bootstrap-amd.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\out\bootstrap-fork.js
OK, so activation failed because the loader barfed. But WTF does importing CSS have to do with support-color?
Remove the import and it runs just fine. I really don't know how to respond to this; it's not clear to me why a demand for a stylesheet should cause that error. At this point I look to others for guidance and advice.
Remove style-loader from webpack.config.js to fix the error.
Pull the CSS as a string like this. Note the abbreviated path.
const cssPath: string = "highlight.js/styles/atelier-dune-light.css";
const theCss: string = require(cssPath).default.toString();
You do not need the import statement, the use of require will cause Webpack to bundle the files, but you still have to remove style-loader to avoid the loader error.

AWS: Steps to pass a node.js application to EC2

I'm newbie with AWS and I'm developing a web application with node.js and react.js. My application works fine in my laptop but I want to upload it to AWS EC2.
When I simulate a production environment in my laptop, I have a /dist folder where are all the code of the front end and the server code is in /src/server folder.
I have uploaded my app to EC2 and now I'm a little bit lost about the next steps.
First, I would like if there is any way to download the modules only if they are not installed
Second, I would like to know if its mandatory to use babel in this environment, because in all tutorial that I have followed to make the development these modules are always installed like a dev depencies. So, is it now mandatory to move all babel modules to dependencies? Right now, my script to this two steps is:
npm -i --production && cross-env NODE_ENV=production babel-node src/server/server.js
If I change babel-node for node then I've got an error with "import" command because I'm not using babel.
My scripts are:
Is there to make a build like I do for the front-end code but for the server code? How can I do it?
Fourt, the server who will be listening the calls to the api will be node server and this will get when I finish to make correctly my aws-start script. But ... Which is the best option to server the front-end pages?
Sorry, I've got too many questions because this is my first app in AWS.
Edit I:
Following the wise advices of #Corrie MacDonald when I build my code I've got this files and folders:
Next, I modify my aws-start script:
npm i --production && cross-env NODE_ENV=production node dist/assets/js/bundle.js
But, I've got this error:
What am I doing wrong?
Edit II:
My webpack.config.babel.js file is:
import path from "path";
import HtmlWebpackPlugin from "html-webpack-plugin";
import MiniCssExtractPlugin from "mini-css-extract-plugin";
const devMode = process.env.NODE_ENV !== "production";
console.log("devMode: " + devMode);
module.exports = {
entry: "./src/client/index.js", //set entry file
// Resolve to output directory and set file
output: {
path: path.resolve("dist/assets"),
filename: "js/bundle.js",
publicPath: "/assets" //It's mandatory to define this publicPath to get access to the website when we reload pages
//or we access to them directly with url's which have directories of second level like
//http://localhost:4000/directory-level-1/directory-level-2
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/client/index.html", //where is our template
filename: "../index.html", //where we are going to put our index.html inside the output directory
minify: {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
}
}),
new MiniCssExtractPlugin({
filename: "css/bundle.css",
minify: {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
}
})
],
//It help us to detect errors.
devtool: "source-map",
// Set dev-server configuration
devServer: {
inline: true,
contentBase: './dist',
port: 3000,
historyApiFallback: true
},
// Add babel-loader to transpile js and jsx files
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use:[
{
loader: "babel-loader",
query: {
presets: [
"#babel/preset-react"
]
}
}
]
},
{
use: [
devMode ? "style-loader" : MiniCssExtractPlugin.loader,
"css-loader"],
test: /\.css$/
},
{
test: /\.scss$/,
use: [
{
loader: "style-loader"
},
{
loader: "css-loader",
options: {
sourceMap: true
}
},
{
loader: "saas-loader",
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: "url-loader",
options: {
limit: 10000,
publicPath: "/assets/images/",
outputPath: "./images/"
}
},
{
test: /\.(eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 10000,
publicPath: "/assets/fonts/", //It's mandatory to get access to the fonts when we reload pages or access directly
outputPath: "./fonts/"
}
}
]
}
}
Edit III:
This are the folders of my development environment:
How you can see when I make a build I create the /dist folder with the front-end code, but my server code still being in /src/server folder. How can I create a /dist folder for my server code? Is that possible?
Without going into a lot of detail about automated building procedures, the steps usually go as follows:
Build Code
-- Here, your source code is built and transpiled into a distributable format, which usually goes into a dist/ folder.
Upload your distributable code.
-- Here, all of the files you have built should be uploaded (manually or automatically) to your EC2 instance.
Run a startup script
-- Here, any project startup code should be run in order to actually start your server.
You don't need babel in production because your project should already have been built by that point. However, if you are building on the EC2 instance, instead of just uploading your dist, then you will need it.
In order to turn your EC2 into a routable, reachable web server, you will need to configure some security and routing policies on AWS. You will need to ensure that the instance has a routable IP (or you can use the automatically generated DNS provided by AWS). Secondly, you'll need to ensure that your security policy allows port 80 (at the very least, and any additional ports you need to interact with the server - for HTTPS, SSH or something else.)
Once you have all this in place, you should be good.
EDIT
If you want to serve static HTML pages, you will have to ensure that you have set up your EC2 container as a web server with something like Apache. However, I would recommend that you run your Node Server exclusively from the server and host your static webpack bundle on S3 as a static website.
EDIT 2
Here's an introduction to setting up your EC2 instance for node. - https://medium.com/#nishankjaintdk/setting-up-a-node-js-app-on-a-linux-ami-on-an-aws-ec2-instance-with-nginx-59cbc1bcc68c
Here's an introduction to setting up a static website with S3. - https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html

Angular 5 and Wordpress

I am attempting to setup a project that uses both Angular 5 and Wordpress. Currently my solution allows the serving of both applications using node. From the root directory I run "node index.js" to run wordpress, and in a separate terminal, in a subdirectory I run "ng serve" to run the angular implementation.
Is it possible to run both angular and wordpress on the same terminal window? An example being, by typing "node index.js" in the root directory, can I serve both the angular application in a subdirectory and the wordpress through that one console?
My projects are pretty bare but here is some base code:
/index.js
const express = require('express')
const epf = require('express-php-fpm')
const options = {
// root of your php files
documentRoot: __dirname + '/wordpress',
// extra env variables
env: {},
// connection to your php-fpm server
// https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener
socketOptions: { port: 9000 },
}
const app = express()
app.use('/', epf(options))
app.listen(3000)
/subproject/protractor.conf.js
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
Thank you.
I am working on a new plugin, Xo for Angular that may provide a solve for the use case above.
https://wordpress.org/plugins/xo-for-angular/
Xo gives you the option to load an Angular App as a theme with WordPress serving only as the management interface. Routes can be generated dynamically so all pages and posts are instantly viewable on the front-end without needing to recompile.
For local development I recommend setting up either apache or nginx using a tool like XAMPP. I have detailed the setup I use for my own local development here: https://github.com/WarriorRocker/angular-xo-material
Once you have wordpress running through a server like apache you can then just run ng build and let Xo load your App/theme through the main front-end. Alternatively you can also run with ng serve for rapid development.
In production you can either have Xo load your App and inject wp_head/wp_footer as necessary (Live Redirect Mode) or redirect all front-end requests to your App's dist index.html (Offline Redirect Mode).
Additional docs (work in progress): https://angularxo.io/

How to bundle NodeJs Application?

Consider I have been done with my NodeJs with Express and MongoDB Application. I can bundle up my application to deliver the same to client but in that case client have to install all required npm modules and change mongoDB connection url. So to counter this issue:
Is there any other way to bundle my application so client do not need to install any npm modules to run application? If yes, then how client can connect to his mongodb?
pkg by Vercel works really well for me. It bundles everything into a single executable that runs out of a terminal. This makes it really easy to distribute.
To connect to a Mongo instance, you would have to have some kind of configuration file that the user edits. I recommend putting into the user data folder (Application Support on Mac and AppData on Windows), but you could have it sit right next to the packaged executable.
You can use good old webpack by setting it's target. here is an example webpack.config.js file for node:
import webpack from 'webpack';
export default {
entry: "./server.js",
output: {
// output bundle will be in `dist/buit.js`
filename: `built.js`,
},
target: 'node',
mode: 'production',
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
})
],
};

Hosting an angular-fullstack Yeoman Site on IIS

I have a project built using the angular-fullstack generator for Yeoman. I would like to deploy this to a Windows Server running IIS. I have successfully generated the "dist" folder using Grunt and moved the "public" and "server" folders with files to my IIS box.
How do I configure my Windows Server to host my application? Do I need to have two IIS sites (one for "public" and one for "server")? Do I need to install grunt, bower, etc. on the Windows Server?
You don't have to manually install grunt nor bower. Install locally the node components declared in package.json using the following comman:
npm install
The angular-fullstack generator creates a Node.js application, so all you have to do is run the server side application. Run /server/app.js with Node.js
You can check how to run Node applications inside IIS here:
http://www.hanselman.com/blog/InstallingAndRunningNodejsApplicationsWithinIISOnWindowsAreYouMad.aspx
You have to deploy the application on iisnode
the do the right configuration for you web.config file I currently are able to run the application using the nodejs server but not in the iisnode applications because my web.config file still working correct I posted a question with more information here
This is just to give you a hint to the way to a solution. It´s not a detailed step by step answer.
If alredy using Grunt, you can use this grunt plugin.
It´s a wrapper of the msdeploy.exe command so you need to learn about that here.
Before all of this you need to install Web Deploy on your server. There are serveral strats and posts about this. I choosed using the Remote Agent way.
I manually create the website (don´t know how to do this remotely yet. Working on that. That´s why I found this question) before I deploy. Then I just sync directories in my computer (your /dist folder) and the path in the remote server.
This a piece of my Gruntfile.js with 2 examples defined in the grunt.initConfig()
'Backup' saves in a package (zip file) the current remote directory.
The second task called 'Oper' syncs your current build located on <%= yeoman.dist %>
msdeploy: {
backup: {
options: {
verb: "sync",
source: {
dirPath: '<%= deploy.Config.basePathOper %><%=deploy.Oper.Web %>,computerName=<%=deploy.Config.computerName %>,username=<%=deploy.Config.username %>,password=<%= deploy.Config.password %>'
},
dest: {
package: '<%= deploy.Config.basePathOper %>\\backups\\web_' + grunt.template.today("yyyy-mm-dd-HH-MM-ss") + '.zip,computerName=<%=deploy.Config.computerName %>,username=<%=deploy.Config.username %>,password=<%= deploy.Config.password %>'
}
}
},
Oper: {
options: {
verb: 'sync',
source: {
dirPath: process.cwd() + '\\<%= yeoman.dist %>'
},
dest: {
dirPath: '<%= deploy.Config.basePathOper %><%=deploy.Oper.Web %>,computerName=<%=deploy.Config.computerName %>,username=<%=deploy.Config.username %>,password=<%= deploy.Config.password %>'
}
}
}
The task I created looks something like this
grunt.registerTask('deploy', function (target) {
if (target === 'Oper') {
grunt.task.run([
'msdeploy:backup',
'msdeploy:Oper'
]);
}
});
Don´t forget to load the plugin:
grunt.loadNpmTasks('grunt-msdeploy');

Resources