What can we build today?

Random notes of a Webdeveloper called Mario.

Fasten your seat-belts - launching Flow in progress!

This episode covers the basic setup of a Flow based application including gulp.js frontend workflow. If you follow along, you'll have a working frontend-workflow with SASS compilation, CSS minifying, and an first view of your application that you can access via your Browser.

I hope you enjoy this story or tutorial (I'm still unsure how to call it) - please let me know whether you miss something or liked it, I'm happy to hear from you.

Pre-Requisites

For the next steps to work, you need some pre-requisites (I'll not cover them here in detail as it would make the story very long):

  • a webserver and PHP installed (locally or on a remote server doesn't really matter, as long as you have the next point)
  • shell access so you can execute commands
  • a basic knowledge on how to work with a text based interface (e.g. changing directories similar tasks)
  • a MySQL database and the needed user credentials to fill/use that database (exclusively, not shared with other apps/projects!)
  • composer, the PHP package + dependency manager, installed
  • [Node.js] (https://nodejs.org/en/) installed as a base for Gulp and his friends

My personal setup for the following steps looks like a silver MacBook with a local Nginx+PHP-FPM setup and the mentioned tools installed.

Configure a vHost

This step probably depends a lot on your preferred way of working. In my case, I have MySQL, PHP and Nginx installed locally on my Mac via brew and after adding the following line to /etc/hosts, I can basically reach the frontend of the application by entering http://lomsy.dev/ in my browser's address bar.

127.0.0.1 lomsy.dev

The step above is needed for each single project / vHost you'd setup since the Hosts-File is not capable of wildcards like "*.dev" (which would simplify things a lot).

Nginx in contrary is able to work with such wildcards: I've set up a config that listens for *.dev and deliver the directory /Users/me/projects/$project/Web as the DocumentRoot - so requesting lomsy.dev will deliver the Website/Application from /Users/me/projects/lomsy/Web to the browser. Pretty neat as it reduces the overhead for starting a fresh project.

Install Flow

The following command creates an fresh base installation of Flow v4.0.x in the empty folder "lomsy":

➜  lomsy composer create-project neos/flow-base-distribution . 4.0.x

After a few moments of downloading packages, composer will probably finish installing the base of our project. Calling the application from a browser via http://lomsy.dev/ now shows a friendly "Welcome to Flow" page. If you reach this, a lot is already fine :-)

In case you don't see the welcome page, reading the error-log files of your Nginx and PHP often reveal details of what went wrong. Additionally, Flow itself does some logging - have a look at the files in the subdirectory Data/Logs for details.

Kickstart our package

Next step is to kickstart our own package which will be the base of the functionality we plan to build on:

./flow kickstart:package OpsDev.Lomsy

This kickstarts an empty application in Packages/Application/OpsDev.Lomsy/.

Remove unused stuff

Just have a look into the composer.json file and cleanup the meta-data about your project if you like.

The base-distribution contains the Welcome-Package - we'll not use that anymore, so let's remove it. We're also removing the Behat package as we'll not use it for now (but it would get installed on each deployment run).

➜  lomsy composer remove neos/welcome
➜  lomsy composer remove neos/behat

This will also remove the routing config that led to display the nice welcome page from the Welcome-Package when requesting http://lomsy.dev/

Add a basic route

since we'd like to "route" the path / directly into LOMSY, we'll have to create two things: A Routes.yaml file in our Package - and then we need to include this new file via the configuration:

Packages/Application/OpsDev.Lomsy/Configuration/Routes.yaml:

-
  name: 'Redirect to LOMSY Welcome Screen'
  uriPattern: ''
  defaults:
    '@package':    'OpsDev.Lomsy'
    '@controller': 'Standard'
    '@action':     'index'
    '@format':     'html'

Packages/Application/OpsDev.Lomsy/Configuration/Settings.yaml:

Neos:
  Flow:
    mvc:
      routes:
        'OpsDev.Lomsy':
          position: 'start'

Just visit http://lomsy.dev/ with your browser again - you shouldn't see the Welcome page again, but instead a very basic output from your own package. Sounds great from the technical side - but somehow doesn't really look nice. So let's beautify this output with some styling in the next step.

Time for Gulp.js

Install gulp and some depending packages:

➜  lomsy yarn add gulp gulp-sass gulp-clean-css bulma

Now create some sass file and include bulma in it. Bulna is the CSS mini-framework I chose as a very simple and light-weight base. Of course we could "merge" the two parts (Bulna and our custom styles) directly via Gulp - but importing bulna this way allows us to override some Sass variables and customize the output and rendering of the CSS framework:

Application/OpsDev.Lomsy/Resources/Private/Scss/lomsy.scss

// override some variables
$primary: #0c8599;

// import bulma base
@import '../../../../../../node_modules/bulma/bulma.sass';

// add custom styles
.nav {
  margin-bottom: 2rem;
}
.content h1 {
  margin-top: 1em;
}

gulpfile.js:

var gulp = require('gulp');
var sass = require('gulp-sass');
var cleanCSS = require('gulp-clean-css');

gulp.task('sass', function () {
    gulp.src('./Packages/Application/OpsDev.Lomsy/Resources/Private/Scss/lomsy.scss')
        .pipe(sass())
        .pipe(cleanCSS({keepBreaks:true, processImportFrom: ['!fonts.googleapis.com']}))
        .pipe(gulp.dest('./Packages/Application/OpsDev.Lomsy/Resources/Public/css/'));
});

gulp.task('default', ['sass'], function() {
    gulp.start('watch');
});

gulp.task('watch', function() {
    gulp.watch([
        './Packages/Application/OpsDev.Lomsy/Resources/Private/Scss/*.scss'
    ], ['sass']);
});

Now call gulp and let it do it's job, after that you should have the compiled CSS file in `Packages/Application/OpsDev.Lomsy/Resources/Public/css/lomsy.css which you then can include into your Fluid layout:

Packages/Application/OpsDev.Lomsy/Resources/Private/Layouts/Default.html

(...)
<link href="{f:uri.resource(path: 'css/lomsy.css', package: 'OpsDev.Lomsy')}" media="screen" rel="stylesheet" type="text/css" />
(...)

Then call http://lomsy.dev/ again - it should of course still render text like "Index view of Standard controller" - but nicely styled from now.

One final step is missing for the "base styling": Prepare the Fluid template in a way it renders what we want so it just fits to Bulma. The following two changes add a navigation bar on the top + a very basic containered setup.

First add the following snippet as the <body> tag of the Layout:

Application/OpsDev.Lomsy/Resources/Private/Layouts/Default.html

<body>
    <nav class="nav has-shadow">
        <div class="container">
            <div class="nav-left">
                <a class="nav-item logo-text">
                    <bold>LOMSY</bold>
                </a>
                <a class="nav-item is-tab is-hidden-mobile is-active">Home</a>
            </div>
            <span class="nav-toggle">
            </span>
            <div class="nav-right nav-menu">
                <a class="nav-item is-tab is-hidden-tablet is-active">Home</a>
                <a class="nav-item is-tab">
                    Username
                </a>
                <a class="nav-item is-tab">Log out</a>
            </div>
        </div>
    </nav>

    <div class="content">
        <div class="container">
            <f:flashMessages class="flashmessages" />

            <div class="columns">
                <f:render section="Content" />
            </div>
        </div>
    </div>
</body>

And then change the template to contain:

Application/OpsDev.Lomsy/Resources/Private/Templates/Standard/Index.html

<f:layout name="Default" />

<f:section name="Title">Welcome to Lomsy!</f:section>

<f:section name="Content">
    <div class="column">
        <h1>A freshly created Fluid template!</h1>
        <p>Some data set by the controller:</p>
        <ul>
            <f:for each="{foos}" as="foo">
                <li>{foo}</li>
            </f:for>
        </ul>
    </div>
</f:section>

Now requesting http://lomsy.dev/ shall shine in a basic styling - isn't it?

Versioning the code, maybe?

I version almost everything I code with Git - even this blog post by the way is versioned via Git. Thus I think it's a good time now to think about versioning what you're building:

First step is creating a git-repo in the current directory:

➜  lomsy git init
Initialized empty Git repository in /Users/me/projects/lomsy/.git/

The .gitignore file that ships with the Flow Base-Distribution doesn't fit my needs, so I tend to change it. Main reason is that I don't want to ignore stuff I need - and not version stuff that is anyway overwritten/imported via composer or the npm package manager:

.gitignore

/.idea/
/node_modules/
/Data/
/Web/
/bin/
/Readme.rst
/Upgrading.rst
/flow
/flow.bat
/Packages/Framework/
/Packages/Libraries/
/Build/BuildEssentials/
/Build/Behat/

Now add everything that's around and create your initial commit:

➜  lomsy git add .
➜  lomsy git commit -m "Initial commit"

Well, then add a Git repository on your preferred Git-Hosting - be it Github, your own Gitlab instance - or some other service. Basically it doesn't matter - and highly depends on what you plan to do with the versioned application code. I'll use Gitlab and deploy via Gitlab CI later on, so after adding an empty project repository on Gitlab, add the remote and push your versioned code to it:

➜  lomsy git remote add origin git@mygitlab.domain.tld:me/lomsy.git
➜  lomsy git push -u origin master

Next steps

Reaching this point, you'll have your basic application ready to be shipped and deployed the first time - read on in the next post of this series, how to do that: Part 3, Deploying a Flow application with Gitlab CI