In the past I always bundled my Angular 1 and Rails apps together and typically used heroku, which has worked great for me. Now that I'm over to Angular 2 I want to separate out my Angular and Rails code. I've created a very basic Angular 2 app via the Angular-Cli, but I haven't been able to figure out how to deploy it to Heroku. I'm not using expressjs or anything like that. Anyone figure it out yet?
Ok I came up with a solution. I had to add a very basic PHP backend, but it's pretty harmless. Below is my process.
First setup a heroku app and Angular 2 app.
Create your heroku app
Set the heroku buildpack to heroku/php
heroku buildpacks:set heroku/php --app heroku-app-name
Create a project via Angular-Cli
Add a index.php file to /scr with the below snippet
<?php include_once("index.html"); ?>
Add a Procfile to /scr with the below snippet
web: vendor/bin/heroku-php-apache2
Added /deploy to the .gitignore
Now I used a npm package to push a tarballs to heroku
Here's a simple package to upload the tarball, https://www.npmjs.com/package/heroku-deploy-tarball
npm i heroku-deploy-tarball --save
I'm also using tar.gz to create the tarball
npm i tar.gz --save
Then I created the deploy.js file at the root of my projecdt with the following code. I first run the buildCommand specified and then move the index.php and Profile to the dist folder. I then tarball the entire dist folder and it gets uploaded to heroku.
var deploy = require('heroku-deploy-tarball');
var targz = require('tar.gz');
var exec = require('child_process').exec;
var requestedTarget = process.argv[2];
if (!requestedTarget) {
console.log('You must specify a deploy target');
return;
}
var targets = {
production: {
app: 'heroku-app-name',
tarball: 'deploy/build.tar.gz',
buildCommand: 'ng build --prod'
}
}
var moveCompressFiles = function (callback) {
exec('cp ./src/index.php ./dist/index.php',
function(err) {
if(err)
console.log(err);
console.log('index.php was copied.');
});
exec('cp ./src/Procfile ./dist/Procfile',
function(err) {
if(err)
console.log(err);
console.log('Procfile was copied.');
});
new targz().compress('./dist', './deploy/build.tar.gz',
function(err){
if(err)
console.log(err);
else
callback();
console.log('The compression has ended!');
});
};
console.log('Starting ' + targets[requestedTarget].buildCommand);
exec(targets[requestedTarget].buildCommand, {maxBuffer: 1024 * 500}, function(error) {
if (!error) {
console.log(targets[requestedTarget].buildCommand + ' successful!');
moveCompressFiles(function () {
deploy(targets[requestedTarget]);
});
} else {
console.log(targets[requestedTarget].buildCommand + ' failed.', error);
}
});
Now just run node deploy production and it should deploy to heroku.
Edit
Just got word from heroku that they are working on an experimental buildpack that would allow for static sites like this. Here is the link to the build pack.
Related
I have a big problem with a system I just created.
I did the standard installation of Laravel 8 with jetstream using the docker and laravel sail...
However, I am not able to do the npm run hot or npm run watch to auto reload or browser sync...
My files are standard with laravel 8 and I haven't made any changes to the code yet.
Informations:
Laravel: v8.41.0
PHP: PHP v8.0.5
Jetstream: v2.3.5
npm: v7.7.6
NodeJS: v15.14.0
my webpack.mix.js looks like this:
const mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel applications. By default, we are compiling the CSS
| file for the application as well as bundling up all the JS files.
|
*/
mix.js('resources/js/app.js', 'public/js').vue()
.postCss('resources/css/app.css', 'public/css', [
require('postcss-import'),
require('tailwindcss'),
])
.webpackConfig(require('./webpack.config'));
if (mix.inProduction()) {
mix.version();
}
my webpack.config.js looks like this:
const path = require('path');
module.exports = {
resolve: {
alias: {
'#': path.resolve('resources/js'),
},
},
};
I have also tried to change the two webpacks with some information I found earlier in research, but really nothing is working, would there be a way for Hot Reload and Browser Sync to work together with Laravel Sail?
While a browsersync script is already included in app.blade.php I did not get it to work either. I removed that line and expanded my webpack.mix.js as follows:
mix.browserSync({
proxy: 'YOURDOMAIN.test',
host: 'YOURDOMAIN.test',
open: 'external'
});
Then run npm run watch- probably twice because it's going to install browsersync - and it's working.
open: 'external' save me ( same i use valet and https )
.browserSync({
proxy: 'https://app.tunnel.test',
host: 'app.tunnel.test',
open: 'external',
https: {
key: homedir + '/.config/valet/Certificates/' + domain + '.key',
cert: homedir + '/.config/valet/Certificates/' + domain + '.crt',
},
})
Using the electron-boilerplate to create an .exe for windows, it needs to run a .bat file. However, using npm start it works but when it gets packaged with npm run release, it doesn't run the .bat
This is my code for the function
const spawn = require('child_process').spawn;
const bat = spawn('cmd.exe', ['/c', 'Install.bat']);
bat.stdout.on('data', (data) => {
var str = String.fromCharCode.apply(null, data);
addLog(data);
console.info(str);
});
bat.stderr.on('data', (data) => {
var str = String.fromCharCode.apply(null, data);
addLog(data,"error");
console.error(str);
});
bat.on('exit', (code) => {
console.log(`Exit ${code}`);
});
Already checked for child-process
When you run electron via npm start it will typically set the current working directory to the folder for the app (containing your package.json). So it will look for cmd.exe in that folder.
After you build the app and run it, the current working directory might be somewhere else, for example C:\\ (on Windows). You can find the current working directory with process.cwd().
To find the app folder regardless of how the app is running, Electron provides electron.app.getAppPath().
So you can use it like this:
const path = require('path');
const cmdPath = path.join(electron.app.getAppPath(),'cmd.exe');
const bat = spawn(cmdPath, ['/c', 'Install.bat']);
I'm trying to create an easy workflow for package development and was hoping someone could pint me in the right direction. In short, once a css file has been updated I want to be able to run a command (php artisan vendor:publish --force) to automatically publish the files.
Can this be done with Elixir and if so could anyone point me in the right direction?
regards
This was incredibly useful to get me on the right track, but I found a slightly simpler solution that I thought I would share:
var elixir = require('laravel-elixir');
var gulp = require("gulp");
var shell = require("gulp-shell");
elixir(function(mix) {
mix.task('publish_assets', ['resources/assets/**/*.scss', 'resources/assets/**/*.js']);
});
gulp.task('publish_assets', shell.task([
"php ../../../../artisan vendor:publish --tag=public --force"
]));
It watches all of the js and sass files for changes and runs the publish assets task. Mine is set to only publish the "public" tagged files, and a quick note as well, you will need to install the gulp-shell utility (https://www.npmjs.com/package/gulp-shell) for either of these.
if anyone is looking, this works nicely:
var gulp = require("gulp");
var shell = require("gulp-shell");
var elixir = require("laravel-elixir");
elixir.extend("publish", function() {
var baseDir = this.assetsDir;
gulp.task("publish_assets", function() {
gulp.src("").pipe( shell( [
"php ../../../artisan vendor:publish --force",
"cd ../../../ ; gulp"
]));
});
this.registerWatcher("publish_assets", [
baseDir + '**/*.scss',
baseDir + '**/*.js'
]);
return this.queueTask("publish_assets");
});
In my app I use letsrate gem, on development all work fine, but on production stars doesn't show why?
letsrate.js.erb file
$.fn.raty.defaults.path = "/assets";
$.fn.raty.defaults.half_show = true;
$(function(){
$(".star").raty({
score: function(){
return $(this).attr('data-rating')
},
number: function() {
return $(this).attr('data-star-count')
},
click: function(score, evt) {
$.post('<%= Rails.application.class.routes.url_helpers.rate_path %>',
{
score: score,
dimension: $(this).attr('data-dimension'),
id: $(this).attr('data-id'),
klass: $(this).attr('data-classname')
},
function(data) {
if(data) {
// success code goes here ...
}
});
}
});
});
$.fn.raty.defaults.path = "/assets";
It works on development but doesn't work on production, I think it doesn't work because in production after assets precompile all images move to the public/assets path
What do I need to do to show images?
mysite.com/assets/star-on-287807403acda8ff0b61388109ea5b6e.png
my images "stars" on this url
1 step: Please paste the following lines to application.js file:
//= require jquery.raty
//= require letsrate
2 step: Execute the following cmd line in your terminal:
rake assets:precompile RAILS_ENV=production
3 step: Copy .png files from /images folder into /public/assets directory
star-half.png
star-off.png
start-on.png
4 step: execute the following cmd line in your terminal:
rails s -e production
I am using NetBeans IDE environment, Rails 4.2 and letsrate gem 1.0.9
I have a rake task that will generate a particular CSV file. I would like to be able to download that CSV file that is going to be placed in /tmp.
My application is hosted in Heroku. How can I download that CSV file?
If you just want to do a one off download, you could try using heroku exec. The exec command allows you to create an SSH connection to a dyno - https://devcenter.heroku.com/changelog-items/1112
First, figure out the file path. You can run bash, then do usual bash commands like ls:
heroku ps:exec -a <myapp> bash
Next, use cat to read the file, and pipe the output to a local file:
heroku ps:exec -a <myapp> cat tmp/myfile.csv > mylocal.csv
The /tmp directory on Heroku is exactly that – temporary. Even if you store the file in the /tmp file, it won't be persisted for long enough that any users will be able to access it. Instead, you should look into an integrated storage solution like Amazon AWS.
With that in place, your users should be able to access those CSV files directly from your storage host without needing to tie up any Heroku dynos/resources.
why is it necessary to place it in tmp folder? if you generate something it has to be important file not temporal one...
solution is easy, just setup your rake task in a way when your file will be saved into public directory (or subdirectory of public directory)
and then you can open/download your export.csv using
http://your-domain/[subdirectory-in-public-directory]/export.csv url
Files in the tmp directory are emptied everyday, tmp directory lives #:
/app/tmp
where app is the root directory
To download files from it you can read the file and convert it into a base 64 and send it back to the client as a data URL:
Server:
let filePath = path.join(__dirname, '..', '..', 'tmp', fileName);
fs.readFile(filePath, {encoding: 'base64'}, function (err, data) {
if (!err) {
let returnData = `data:${mimeType};base64,` + data;
res.json({fileName: fileName, displayName: displayName, base64: returnData})
} else {
console.log(err);
}
});
Client side:
function b64toBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: 'image/jpeg' });
}
var blob = b64toBlob(res.data.base64);
var blobUrl = URL.createObjectURL(blob);
var link = document.createElement("a"); // Or maybe get it from the current document
link.href = blobUrl;
link.download = res.data.displayName;
document.body.appendChild(link)
link.click()