Stuff I'm Up To

Technical Ramblings

Yarn, npm and Git — July 31, 2018

Yarn, npm and Git

I’m kinda new to this hosting software externally. I’ve been happy using Gitlab for internal private projects, but recently I’ve been forking and reworking the work of others to include into my own.

So I thought I’d try publishing them back out to npmjs.com and github,com.

Publishing up to github is pretty straight forward. Using git from the command line to just add, commit and push is all the same, just now with an online repository rather than the internal Gitlab. In fact once the repository is added to the project I’m betting the Atom.io built in Git will handle the committing and pushing.

Recently I decided to have a look at yarn – it uses the npmjs repository just like npm. So far I’m liking it. It’s kinda pretty and I do like the caching.

I pretty much use yarn where ever I would have used npm. So instead of npm init I use yarn initnpm install I now use yarn add. Where I used npm run dev now it’s yarn run dev, and yarn run hot, etc.

Publishing

Now to push my packages up to npmjs. First you have to have an npmjs account, so sign up. Like Github, npmjs is only free for “public” packages. If you want “private”, you have to pay.

Then link yarn and npm up to your npmjs account using login.

$ yarn login
yarn login v1.7.0
question npm username: mynpmjsname
question npm email: me@mail.com 
Done in 32.16s.

Similarly for npm.

This saves an auth token into your .npmrc file so if you’ve supplied the password already you won’t need it to publish with. What I found after pushing up to git and publishing to npmjs was that I was doing things in the wrong order. So used to doing git commit and push, it’s second nature.

Before you git push to github, publish the package to npmjs. Do it this way because it will force a version increment which will do a git commit. Because it will have incremented the version in your package.json.

The name, version and description etc. in your package.json is what will be used by your project.

Because you are likely to want to publish what is probably a private project name (beginning with @) to a public project you’ll need to tell your publish command to make it public, or you’ll get a warning pretty much about about not having subscribed to publish private projects.

$ yarn publish --access=public

When you look at your projects in your npmjs.com profile you’ll see your fresh project ready for everyone to consume!

$ yarn publish
yarn publish v1.7.0
[1/4] Bumping version... 
info Current version: 1.8.1 
question New version: 1.8.2 
info New version: 1.8.2 
[2/4] Logging in... 
[3/4] Publishing... 
success Published. 
[4/4] Revoking token... 
info Not revoking login token, specified via config file. 
Done in 8.85s.

But that’s how easy it was to publish up to npmjs!

Now you’ve pushed to npmjs, you can do a git push to deliver the same project up to Github.com now with the new version.

References

https://yarnpkg.com/en/docs/creating-a-package

Advertisements
Laravel 5.5 and Bootstrap 4 — July 30, 2018

Laravel 5.5 and Bootstrap 4

Laravel 5.5 ships with Bootstrap 3. To make it use Bootstrap 4 you need to make a few changes.

resources/assets/js/bootstrap.js

Change require('bootstrap-sass') to require('bootstrap')

resources/assets/sass/app.scss

Change @import('~bootstrap-sass/assets/stylesheets/bootstrap'); to @import "~bootstrap/scss/bootstrap";

resources/assets/sass/_variables.scss

Change $font-size-base: 14px; to $font-size-base: 1rem;

Remove Bootstrap 3 using

$ npm remove bootstrap-sass

Install Bootstrap 4 using

$ npm install bootstrap

Rebuild your project

$ npm run dev
Laravel Forgotten User Password — July 27, 2018

Laravel Forgotten User Password

I rarely need to do this and it’s always something I Google when I do. But when I forget the admin users password on my dev app I need to reset it.

Easiest way is to use Laravel’s ‘tinker’

$ php artisan tinker
>>> use App\User
>>> $user = User::where('username', '=', 'admin')->first()
>>> $user->password = bcrypt('mysecret')
>>> $user->save()

 

 

Vuetable-2 — July 26, 2018

Vuetable-2

Previously I’ve used Datatables.net to build my tables on the Laravel blade templates for user interface. Now I’ve been migrating over to Vue.js I thought I’d look at another option – more Vue.js centric.

This is where vuetable-2 (not to be confused with other vue components of a similar name!) came in. I tried a lot of other vue tables and most of them had a dependency for jQuery. I really wanted one that didn’t use jQuery – I know Bootstrap has it as a dependency, but if I ever decide to remodel the UX using something like Material Design, I’d have no need to include jQuery.

As a component I needed to do a lot of work to configure it to work with my setup. But only really because I wanted it to work with Bootstrap 4 and fontawesome. So I had to build vue component templates that presented me with the correct structure and classes for the pagination and search.

The examples in the Gists relate to my admin interface to manage a Laravel user model of users and roles.

(see gists below)

Continue reading

JWTAuth, Laravel and Vue.js —

JWTAuth, Laravel and Vue.js

The past few days have been rather eventful trying to get JavaScript Web Tokens (JWT) to authenticate my Laravel, Vue.js environment.

As per my previous post: Laravel and Vue.js Authentication where I followed the very useful post this did in fact work for getting me around inside the vue router. But once I started making my own Axios calls or using api calls withing my vue’s I ran into a lot of problems with every time I called an api I got unauthenticated.

The solution for me was to move to the tyson/jwt-auth development branch for 1.0 and then configure things from there.

As far as the linked article goes installing the npm/yarn vue side dependencies for @websanova/vue-auth is all good. This sets the vue environment up to handle the response Authorization header to pass back into the Axios requests.

But what we need to get working is the Laravel/PHP environment to actually authenticate and send out the necessary Authorization header. That’s where I had to go “off piste” and do it differently.

Using: Laravel 5.5, PHP 7.2, JWTAuth 1.0(dev) – as of today 26 July 2018.

Continue reading

Laravel and Vue.js Authentication — July 25, 2018
Laravel Vue.js and API Routes — July 23, 2018

Laravel Vue.js and API Routes

I ran into a problem where I’ve started to deploy Vue components using the Vue Router from within Laravel. As soon as I enabled the Vue route for /{any} I lost access to the api routes.

routes/web.php

Route::get('/{any}', function () {
  return view('home');
})->name('home')->where('any', '.*');

Auth::routes();

app.js

const routes = [
  {
    path: '/',
    name: 'home',
    component: home
  }, {
  ...
  }, {
    path: '*',
    name: 'notFound',
    component: notFound
  }
]

I took a look at the Laravel RouteServiceProvider.php and noticed that the order of the web and api providers put the web first, so I swapped them around and now my api’s are back in business.

/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
  $this->mapApiRoutes(); // Needs to be first

  $this->mapWebRoutes();

}

 

 

Laravel 5.5 and Hot Module Reload — July 20, 2018

Laravel 5.5 and Hot Module Reload

Revisiting a previous post  about vue-cli 3 and hmr I tried to get HMR going in a similar fashion through Laravel-mix.

First mistake to make is that laravel-mix does not need BrowserSync for HMR. So don’t install it or configure it in the webpack.mix.js file.

HMR on Laravel 5.5 is loaded by running the package.json “hot” script:

$ npm run hot

It compiles the assets and sits there doing apparently nothing. When actually it’s listening on localhost:8080 for HMR/WDS connections. Whilst in this state if you open another session and serve your project using artisan, HMR just works…

$ php artisan serve

… if you are developing on the same “localhost” as the HMR and artisan server are running on.

But what if you’re not?

I tend to fire up a virtual host with Laravel installed so can’t access it as “localhost” I must use one of it’s public interfaces such as 192.168.56.2.

To make laravel-mix HMR run on one of your public interfaces you’ll need to edit you webpack.mix.js file and add it the following as per your serving host:

mix.options({
  hmrOptions: {
    host: '192.168.56.2',
    port: 8080
  }
});

In your blade template ensure you refer to your assets using the form src="{{ mix('js/app.js') }}" as using it like this handles adjusting the host in the blade based on if you are running the hot script or not.

You MUST run two sessions to use HMR. One to run the hot compiler and one to serve the php environment with artisan. I’ve had frustrating times trying to use & for task spawning.

In session one:

$ npm run hot

In session two:

$ php artisan serve --host 192.168.56.2

Visit your app at: http://192.168.56.2:8000 and you’ll get your artisan served php project.

If you inspect the page in your browser you’ll see the mix src becomes //192.168.56.2:8080/app.js because of the webpack.mix.js change – NOT the artisan serve.

A Further Note

The ability to overwrite the config for hmtOption looks like a laravel-mix ^2.0 thing. I just spent an hour wondering why another project was failing to run on anything other than localhost when the option set.

Upgrading to laravel-mix ^2.0 in composer.json​ resolved the problem.

 

Laravel storage/logs Error — July 19, 2018

Laravel storage/logs Error

A regular issue for me is failing the initial deployment of a git clone Laravel server using Nginx. It’s almost always because I forget to create and give permissions to the Nginx user www-data.

UnexpectedValueException
There is no existing directory at "/var/www/myproject/storage/logs" and its not buildable: Permission denied
Then even if I do sort the permissions here it fails again with:
InvalidArgumentException
Please provide a valid cache path.
This is because the storage/framework path and subfolders don’t exist. You need to create folders and make sure the www-data user has read/write/create permissions:
$ mkdir -p storage/framework/cache
$ mkdir -p storage/framework/sessions
$ mkdir -p storage/framework/views
$ sudo chgrp www-data storage -R
$ sudo chmod g+rwx storage -R
vue-cli 3 and hmr — July 18, 2018

vue-cli 3 and hmr

What a nightmare I’ve had. Trying to figure out how to run a dev server with HMR (Hot Module Reload) on a virtual host that has two interfaces – one NAT and one Host Only adapter!

Why the two interfaces? Well I have to NAT one out from the guest OS so traffic looks like it comes from my business PC that uses network authentication. But NAT means I have no access back to the dev server as it uses an ip of 10.0.2.15 (typical virtual box behaviour).

So to gain access to the dev server from my host I then use another NIC in the virtual guest that uses the “Host Only Adapter”. So this ends up using a static IP address of 192.168.56.2 – again typical virtual box behaviour.

So I can access the virtual guest as http://192.168.56.2:8080 to connect to the webpack dev server, but then I see errors in the client browser console:

+ [HMR] Waiting for update signal from WDS
+ [WDS] Disconnected

When I expanded the [WDS] Disconnected message I could see the clue being:

./node_modules/webpack-dev-server/client/index.js?http://10.0.2.15:8080/sockjs-node

It’s obviously telling my client to use the wrong network interface for the websockets/sockjs connection used by HMR.

How to fix it was a mystery. I had to trawl until I found the @vue\cli-service\lib\serve.js file. In here it starts the sockjs with options like this:

const publicOpt = projectDevServerOptions.public
const sockjsUrl = publicOpt ? `//${publicOpt}/sockjs-node` : url.format({
  protocol,
  port,
  hostname: urls.lanUrlForConfig || 'localhost',
  pathname: '/sockjs-node'
})

This meant I could look to the vue-config.js​ file in the root of my project ad set the ‘public’ variable accordingly. I also set the proxy option to handle the fact I’m not developing on the same server.

// vue.config.js
module.exports = {
  devServer: {
    useLocalIp: false,
    proxy: 'http://localhost:8080',
    public: '192.168.56.2:8080',
  }
}

Then I started the dev server using yarn, I could also use npm I guess.

$ yarn serve
...
DONE Compiled successfully in 1002ms 21:39:53

  App running at: 
  - Local: http://localhost:8080/ 
  - Network: http://10.0.2.15:8080/

Now when I edit code and webpack recompiles, the HMR works and the browser updates!

 

Building a Debian Development Server — July 13, 2018

Building a Debian Development Server

When I setup a development system there are a few steps I follow to get everything working together.

The aim is to get everything installed to provide php and composer, node, nginx, mysql and Laravel as a base to build on.

Install Debian

I take the latest amd64 version using a network installable iso. This way if I use an older 9.1, 9.2, 9.3 version iso, being a netinst version I’ll end up with the latest in that series as it downloads from the net.

Mostly making a 50GB disk is more than enough, as it’s thin provisioned on a virtual, space isn’t really a concern. When it comes to partitioning I’ve learned to take the easy option and create one partition to mount all filesystems into it.

Capture1

As it’s a development platform I never install a desktop environment. I never need to use any GUI programs on the server. The only options I choose to install are the standard system utilities and the ssh server.

Capture2

Out of personal preference, once up and running I install sudo, zsh, curl and git.

# apt-get install sudo zsh curl git

Then I add my non-root user to the sudo group so I can stop using root and use my regular user account to ssh onto the dev server..

# usermod -aG sudo [user]

Setup OhMyZsh

I like using zsh and the OhMyZsh which is why I installed curl and git. So logon as your non-root user.

$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

Then I edit the ~/.zshrc file and change the theme to “bureau”.

Network Config

If I’m building a Virtual Box guest that runs on my local PC I’ll setup two interfaces. If it’s a virtual on VMWare I’ll just use the one production interface.

On a local Virtual Box I use one interface as NAT, so it gets a DHCP address like 10.0.2.15 which all outgoing traffic is routed by default. Makes life easier on a corporate network where network authentication is required. Using NAT like this means I don’t need to authenticate my guest as it NAT via my physical hosts authenticated interface.

I then setup second interface so I can connect to what is being served from the guest. This is a “host only” interface and means only my local system can connect to it, but because of the NAT the guest will still have access to the corporate network resources/servers.

This means I end up with two devices usually named enp0s3 (NAT) and enp0s8 (Host Only) on Debian.

Using a Static IP (optional)

I choose to make my system with a static IP. Using the Virtual Box DHCP server on a “host only” interface gives out a 192.168.56.101 address to the first guest, 102 to the second and so on. But you can end up with inconsistent IP’s for your hosts. So making them static is a better option IMO.

Edit /etc/network/interfaces and set you host only adapter to static:

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo

iface lo inet loopback

# The primary network interface
allow-hotplug enp0s3
iface enp0s3 inet dhcp

allow-hotplug enp0s8
iface enp0s8 inet static
  address 192.168.56.2
  netmask 255.255.255.0

This way My dev system always gets the static IP I chose for it.

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
  link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
  inet6 ::1/128 scope host 
    valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  link/ether 08:00:27:61:a6:a8 brd ff:ff:ff:ff:ff:ff
  inet 10.0.2.15/24 brd 10.0.2.255 scope global enp0s3
    valid_lft forever preferred_lft forever
  inet6 fe80::a00:27ff:fe61:a6a8/64 scope link 
    valid_lft forever preferred_lft forever
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  link/ether 08:00:27:2b:04:26 brd ff:ff:ff:ff:ff:ff
  inet 192.168.56.2/24 brd 192.168.56.255 scope global enp0s8
    valid_lft forever preferred_lft forever
  inet6 fe80::a00:27ff:fe2b:426/64 scope link 
    valid_lft forever preferred_lft forever

Install PHP

Because we don’t want Apache2 installed you need to install php-fpm which won’t force an install of Apache.

$ sudo apt-get install php-fpm

It will include a load of other php components you need, but no Apache, so you can then choose to move on to Nginx or some other php service.

Add the Laravel php requirements

$ sudo apt-get install php-mbstring php-zip php-xml libpng-dev make gcc g++

The additional module libpng-dev is required for Laravel to build using NodeJS npm. Without libpng-dev, make, gcc and g++, under your Laravel project folder the call to $ npm i fails with errors like:

> pngquant-bin@4.0.0 postinstall /home/user/myproject/node_modules/pngquant-bin
> node lib/install.js
⚠ The `/home/user/myproject/node_modules/pngquant-bin/vendor/pngquant` binary doesn't seem to work correctly
⚠ pngquant pre-build test failed
ℹ compiling from source
✔ pngquant pre-build test passed successfully
✖ Error: pngquant failed to build, make sure that libpng-dev is installed
at Promise.all.then.arr (/home/user/myproject/node_modules/pngquant-bin/node_modules/bin-build/node_modules/execa/index.js:231:11)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)

Install MySQL

As you’ll need a database you’ll want to install MySQL. These days MySQL is installed from the MySQL site by downloading a .deb file which add the Oracle repositories. The version of MySQL in the Debian repositories is MariaDB, a fork of MySQL.

If you go for the Oracle version  you’ll probably need to ensure you use legacy authentication for now.

Include the php drivers as we install the server:

$ sudo apt-get install mysql-server php-mysql

To manage MariaDB using mysql you need to use sudo:

$ sudo mysql -u root
...
MariaDB [(none)]>

Install Composer

Go to your home folder and use the command line install from here: https://getcomposer.org/download/

You’ll end up with a file composer.phar. This is ok if you’re the only one going to use it but I like to put it in /usr/bin as just composer so it is available for everyone.

$ sudo cp ~/composer.phar /usr/bin/composer
$ sudo chmod 755 /usr/bin/composer

Install NodeJS

Install it using a package manager following the steps for Debian

https://nodejs.org/en/download/package-manager/

$ curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
$ sudo apt-get install -y nodejs

Then the first thing I do is update npm.

$ sudo npm i npm -g

Install Samba

Because not all development takes place on a Linux host this will allow us access to shares for Windows clients.

$ sudo install samba

Edit /etc/samba/smb.conf and make some simple changes.

workgroup=[NETBIOS DOMAIN NAME]

Then find [homes] and in that section change:

read only = no
create mask = 640
directory mask = 750

Create a password entry for your non-root user:

$ sudo smbpasswd -a [user]

Then restart Samba

$ sudo systemctl restart smbd

Then when you browse to the server from windows you should see and have access to your home folder eg. \\192.168.56.2\user

Installing Laravel

I prefer to install Laravel as a project using the Create Project method:

$ composer create-project --prefer-dist laravel/laravel [myproject]

This downloads all of the PHP composer prerequisites and delivers the project.

Once the project is created you can go into the folder [myproject] and check you can compile the assets using Node.

$ cd myproject
$ npm i

This will install all of the NodeJS prerequisites used for building/compiling your assets using the Laravel asset management tools – currently Laravel Mix (Based on Webpack). So with the Node modules installed you should be able to run prod and dev builds:

$ npm run dev
$ npm run prod

These should complete successfully.

You can then run Laravel’s built in development server to serve your project:

$ php artisan serve

But in reality this will fire up a pretty useless server listening on the IP address 127.0.0.1 on port 8000. So it’s only accessible from the development server.

As we’re going to need to access it from our client development machine we need to serve on the actual IP of the server. The easiest way of doing this is to serve it on every IPv4 interface on the server (you probably only have one, so it shouldn’t matter). To do this use:

$ php artisan serve --host=0.0.0.0

and if you want to specify the port you can use:

$ php artisan serve --host=0.0.0.0 --port=8001

Now you can access it from any client pointing your browser at http://192.168.56.2:8001 and begin exploring your Laravel project.

More Laravel

Of course serving a version of your project like this isn’t the only way to go. You should continue into dynamically building your assets using npm run watch and maybe even using tools like browserify to make changes happen at the browser end so you’re not building and refreshing all the time.

I also like to move away from a development web server and setup Nginx to handle serving my Laravel Project.

Further Reading

https://warlord0blog.wordpress.com/2017/03/01/ssh-logon-with-private-key/

https://warlord0blog.wordpress.com/2018/05/16/debian-stretch-ntp-time-sync/

https://warlord0blog.wordpress.com/2017/12/12/php7-0-microsoft-sql-driver-debian-stretch/

https://warlord0blog.wordpress.com/2017/03/01/installing-updating-webmin/

 

 

Project scoRPIon – Wake-on-WiFi — July 8, 2018

Project scoRPIon – Wake-on-WiFi

A friend setup his home systems to turn on his PC using Amazon Alexa and tasker to trigger a Raspberry Pi to operate a relay and effectively activate the power button.

What a wonderful idea!

I have a host of Raspberry Pi’s, but instead of Alexa I have chosen the Google Home (Assistant) for my voice control.

My PC is located upstairs from my router and connects using 802.11ac WiFi. Being WiFi that rules out using Wake-on-LAN, which I used to do. So using a RPI to trigger a relay is genius.

Continue reading