How can I deploy / serve a react-based excel office addin? - excel

I am writing an office addin using office-js with React. My addin sideloads and works alright but I'm running into issues deploying it.
Steps to reproduce:
Create a trial react app (addin) using the instructions here: https://learn.microsoft.com/en-us/office/dev/add-ins/quickstarts/excel-quickstart-react and https://github.com/OfficeDev/generator-office.
Sideload the addinusing npm start and everything works well when served via the dev server -- everything works well!
Try serving the add-in statically in one of the two ways (I made sure the manifest is updated appropriately):
HTTP: npm install -g serve and then serve -s dist
or
HTTPS using a server like express:
express = require("express");
https = require("https");
const PORT = 3000;
const SERVER_ROOT = "dist";
var fs = require('fs');
var server=express();
var staticOptions = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now())
}
}
server.use(express.static(SERVER_ROOT, staticOptions));
var sslOptions = {
key: fs.readFileSync('certs/server.key'),
cert: fs.readFileSync('certs/server.crt')
};
https.createServer(sslOptions, server).listen(PORT, function(){
console.log("Server started.");
console.log("Listening on port:" + PORT);
});
On loading the add-in, the task pane is blank.
Firing up a debugger or the F12 IE Chooser tool throws the exception:
0x800a139e - JavaScript runtime error: Office.js has not fully loaded.
Your app must call "Office.onReady()" as part of it's loading sequence
(or set the "Office.initialize" function). If your app has this
functionality, try reloading this page.
6.Opening the html page on a web browser complains that React and ReactDOM are undefined (happens in index.tsx, but I think eventually the modules get loaded) and then subsequently throws the same exception "Office.js is not fully loaded".
-- In case it helps, I'm using react 16.2.0 and I'm on Office 365 desktop, version 1807, build 10325 (monthly channel).
-- Also, is there a way to avoid hosting on a server and just using a manifest (in a shared folder) pointing to another shared folder? I'm thinking browserify or something similar (but browserify didnt work either and I guess webpack might be the reason). [I did see the documentation about deploying addins, but they are not very helpful in this case].

Related

Basic express setup: not sending anything to local port

I created a frontend app and now trying to incorporate backend into it.
ON the same frontend app i added an index.js file in the root directory, and installed express and required it in index.js file.
Very basic setup as below:
const express = require('express')
const cors = require('cors')
const port = process.env.PORT || 3001
const app = express()
app.get('/', (req, res) => {
res.send({
greetings: 'hi'
})
})
app.listen(port, () => {console.log(`Server on port ${port}`)})
Server is successfully on port 3001 as per my terminal, however, on localhost:3001 I'm not seeing any json response I set up in app.get.
It says Cannot GET / instead. When i inspected in devtool(Network) it says 404.
This seems a very straightforward setup, but what could've gone wrong here?
i just figured why. I installed nodemon but my “start” script is “node index.js”. Should’ve used “nodemon index.js”
Working now with nodemon index.ks
Your code is fine, There are no errors, I tested it and it works as expected.
However few things to note, Keep Backend in Seperate folder/dirctory unless required.
Coming back to your question, There are many possiblity such as some modules are not installed properly
try running following command
//this will install if any library is currupt or not installed properly
npm i
if it doesn't work then try clearing cache
Also keep in mind, In nodeJS dev server does not automatically refresh changes, you need to restart server to see changes or you can use dev dependancy called Nodemon (this will auto restart server on saving changes)

How to deploy NextJS application to Linux Server (CentOS 7) - VPS

I've got a question regarding building applications. I'm using simple VPS with node.js support. Now I do not know how to build my next.js application to production.
I want to deploy my application as static files.
I thought that I should use next build && next export then copy out dir to the server but during this process, I faced some issues - when I change route - everything is okay, but if I refresh the page - the page is not found because the server is looking for this file in directories. So how can I deploy my nextjs application in production mode with VPS server and static files?
I tried one thing which is not working fine probably or I did something wrong.
I added nodejs express server with
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({dev});
const router = express.Router();
const handle = app.getRequestHandler();
app.prepare()
.then(() => {
const server = express();
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(3000, (err) => {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
});
and start server with forever library NODE_ENV=production node server.js and it's working fine, but seems this is working in a wrong way - seems it's normal server like in dev mode - so it shouldn't be like that. (I see thunder icon on the right-bottom corner and I see all files which are same as in dev mode).
I want to deploy everything as static files.
Thank you for your help!
After you build and export you need to serve those files somehow. The reason the Express server works is because you are starting a HTTP server to serve the files.
So you need to serve those files either by using a static hosting provider (i.e. Vercel or Amazon S3). Otherwise you should start a server on your linux machine using something like serve to serve it at a port, similar to your Express server serving it as localhost:3000 which is then exposed on your VPS.

Problems running an Angular 9 app in NodeJS

I have a working NodeJS server and an Angular 9 app. I'm able to test the app in development mode, it works perfectly.
But, when I build the app with ng build --prod and try to access it with NodeJS server I get several errors about file load:
Refused to apply style from
'http://localhost:8080/styles.09cf2cc3740ba29d305c.css' because its
MIME type ('text/html') is not a supported stylesheet MIME type, and
strict MIME checking is enabled.
GET http://localhost:8080/runtime.689ba4fd6cadb82c1ac2.js
net::ERR_ABORTED 404 (Not Found)
I have a proxy file in the app to redirect all its petitions to NodeJS:
proxy.conf.json
{
"/api/*": {
"target": "http://localhost:8080",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
}
}
Am I missing something?
proxy.conf.json aims to provide you an easy way to access to backend by rewriting url in development environment, by using ng serve.
For example, by accessing http://localhost:4200/api, in fact, you access http://localhost:3000/api. (so your backend).
But here, you're issue is how to serve Angular files with NodeJS.
Here is a minimal express code which serves an API endpoint /api, and also static files inside public sub-directory.
const express = require('express')
const app = express()
app.use(express.static('public'));
app.get('/api', function (req, res) {
res.send({ message: 'api ok' })
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
Copy all files generated by ng build --prod, (see inside dist folder, and your-app-name subfolder) to public folder.
node app.js
You will be able to access your Angular app at http://localhost:3000, and your Angular app will be able to access your API at http://localhost:3000/api.

Angular / Express hosting

I want to run angular on a linux box without needing node or express. I've created a website but not sure what tech is what, haha. I'm assuming I have a simple web server using express server, see code below.
var express = require ('express');
var app = express();
var path = require('path');
app.use(express.static(__dirname + '/'));
app.listen(8080);
console.log('Magic happens on port 8080');
I start this using the node server command. And the rest of the code is angular-ui.
Do I need to use express (and host this on a node compatible server), or can I just run this thing on a linux box without express? If so, do i need to replace my server.js file (above) with something else? or... Currently it's not working on the linux box, but works locally just fine.
**Edit: I tested an angular 'hello world' app on my shared server, it worked fine. When I run the full angular app on the shared server I get the following error:
Uncaught Error: [$injector:modulerr] Failed to instantiate module routerApp due to:
Error: [$injector:nomod] Module 'routerApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
** edit: In answer to #RobertMoskal 's question below, the angular hello world test that's working on the shared server is basically this:
<input ng-model="name" type="text" placeholder="Type a name here">
<h1>Hello {{ name }}</h1>
And the real app is basically something like this, using ui-view and ng-repeat in the html:
var routerApp = angular.module('routerApp', ['ui.router']);
routerApp.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/home');
$locationProvider.html5Mode(false).hashPrefix("");
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
templateUrl: 'partial-home.html',
// onEnter: scrollContent
})
// ANIMATION AND NESTED VIEWS ========================================
.state('animation', {
url: '/animation',
templateUrl: 'partial-anim.html',
controller: function($scope) {
$scope.animations = [
{ title:'One', url:'http://yahoo.com', bg:'#f8f8f8', width:'160', height:'600', imageAsset:'assets/imgs/web/MyWebsites_1.jpg', paragraph:'some text of some description'},
{ title:'Two', url:'http://google.com', bg:'#f8f8f8', width:'160', height:'600', imageAsset:'assets/imgs/web/MyWebsites_2.jpg', paragraph:'rabbit rabbit rabbit'},
{ title:'Three', url:'http://bambam.com', bg:'#f8f8f8', width:'160', height:'600', imageAsset:'assets/imgs/web/MyWebsites_3.jpg', paragraph:'blahiblahblah'}];
}
})
// GAME VIEWS ========================================
.state('game', {
url: '/game',
templateUrl: 'partial-game.html'
})
// CONTACT VIEWS ========================================
.state('contact', {
url: '/contact',
templateUrl: 'partial-contact.html'
})
});
You need some web server to server your angular app as a "static" asset. This can be apache or nginx or any number of web servers. Most linux distributions make it easy to install them.
You can also go super lightweight with the built in python web server:
cd /var/www/
$ python -m SimpleHTTPServer
You can even host your application for free on github.
In all cases you you just need to make sure that the web server is serving your assets from the correct path. The above python example example you might have your app entry point in /var/www/index.html and it would be served as http://localhost:8000/index.html.

Unable to get connect-livereload to work with express server in gulp task

I am working off of Yeoman's gulp-webapp generator. I have modified my gulp serve task to use my Express server, rather than the default connect server it ships with. My issue is with Livereload functionality. I am trying to simply port the connect-livereload to work with my Express server rather than having to install new dependencies. It's to my understanding that most connect middleware should work fine with Express, so I am assuming connect livereload is compatible with Express 4.
Here are the contents of the relevant tasks in my gulpfile:
gulp.task('express', function() {
var serveStatic = require('serve-static');
var app = require('./server/app');
app.use(require('connect-livereload')({port: 35729}))
.use(serveStatic('.tmp'));
app.listen(3000);
});
gulp.task('watch', ['express'], function () {
$.livereload.listen();
// watch for changes
gulp.watch([
'app/*.ejs',
'.tmp/styles/**/*.css',
'app/scripts/**/*.js',
'app/images/**/*'
]).on('change', $.livereload.changed);
gulp.watch('app/styles/**/*.css', ['styles']);
gulp.watch('bower.json', ['wiredep']);
});
gulp.task('styles', function () {
return gulp.src('app/styles/main.css')
.pipe($.autoprefixer({browsers: ['last 1 version']}))
.pipe(gulp.dest('.tmp/styles'));
});
gulp.task('serve', ['express', 'watch'], function () {
require('opn')('http://localhost:3000');
});
With this simple setup, when I run gulp serve in my cmd everything spins up fine and I can accept requests at http://localhost:3000.
Now if I go and change the body's background color from #fafafa to #f00 in main.css and hit save, my gulp output will respond with main.css was reloaded, as seen in the bottom of this screenshot.
However, my webpage does not update. The background color is still light-grey instead of red.
Is there perhaps a conflict between my express server config and the way gulp handles its files? Is my Express server forcing the use of app/styles/main.css rather than the use of .tmp/styles/main.css? Shouldn't the livereload script handle the injection of the new temporary file?
Thanks for any help.
EDIT:
I was able to move forward a bit by adding livereload.js to the script block of my index file, like so:
<script src="http://localhost:35729/livereload.js"></script>
I am now able to get live changes pushed to the client. Why was this file not getting injected before? How can I ensure this is getting used programatically as opposed to pasting it into my files?
I was able to get past this issue by removing the app.use(require('connect-livereload')({port: 35729})) from my gulpfile, along with a couple of other lines, and having that instantiate in my Express server's app.js file.
My gulpfile's express task now looks like this:
gulp.task('express', function() {
var app = require('./server/app');
app.listen(3000);
});
I added in the connect-livereload just above where I specify my static directory in Express:
if (app.get('env') === 'development') {
app.use(require('connect-livereload')());
}
app.use(express.static(path.join(__dirname, '../app')));
Once I started using this setup, I was getting the livereload.js script injected into my document, and client-side changes are now auto-refreshed just how I wanted.
Hope this helps someone!

Resources