Bootstrap

If you are following the Front End Development theme, then you’ve got your environment set up with Node.js, Grunt, Bower, and you’ve got a Bootstrap app going.

Let’s add a bootstrap form to that index.html file and our css and javascripts.

The form is going to submit to get_primes.php and we included get_primes.js, so we need to build these files also.

Because we built with bootstrap, we have a lot of functionality built in – the css for the form is there, and jQuery is there. We really only have to design the form fields, add the javascript to handle the AJAX on submit, and build a php script to generate the repsonse.

The Prime Form in Action
The Prime Form in Action

Check out the source code: https://github.com/jnodwell/bootstraptest

Grunt – The JavaScript Task Runner

Front End Development – Automation Please!

A lot of front end development centers around repetitive tasks with your CSS and media with minification and compilation, as well as unit testing and lint checking. Automating these kinds of tasks prevents errors and reduces effort. Grunt is a JavaScript task runner with many plugins that handle most, if not all, the tasks you need.

Using Grunt with SASS and Bower to set up Bootstrap for a new project, you can make your project portable and improve the efficiency of your workflow which can lead to increased time for development and enhancements to the project.

I’m going to start by building a web server on my development machine and call it bootstraptest.dev. I use nginx, so I just need to add a new conf file to /etc/nginx/sites-available, link it in /etc/nginx/sites-enabled and restart nginx. (Since I’m running locally, I update my /etc/hosts file on my Mac also.)


server {
  listen                *:80;

  server_name           bootsraptest.dev;
  client_max_body_size 1m;

  root /var/www/bootstraptest;
    index  index.php index.html index.htm;

  access_log            /var/log/nginx/nxv_bootstraptest.access.log;
  error_log             /var/log/nginx/nxv_bootstraptest.error.log;
  location / {


    root  /var/www/bootstraptest;
    try_files $uri $uri/ /index.php$is_args$args;
     autoindex off;
    index  index.html index.htm index.php;


  }
  location ~ \.php$ {


    fastcgi_index index.php;
    try_files $uri $uri/ /index.php$is_args$args;
    include /etc/nginx/fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;

    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_param APP_ENV dev;

  }
  sendfile off;
}

I know I have node.js installed on the server, but if you don’t, click here.

Bower is a package manager which will manage downloading and updating the frameworks and dependencies included in our project. I’m going to install and initialize it from the command line on the server because it isn’t installed on this server yet.


npm install -g bower

We use Bower to install Bootstrap. Once we initialize the bower project, a bower.json file will be initialized that manages the dependencies for all the required includes. After it is initialized, we will install the SASS CSS pre-processor bootstrap project. Other developers will be able to download our project and just run bower install to download project dependencies. Then, we set up the packages.json file that tracks our Node packages.


bower init
bower install bootstrap-sass --save
npm init

If not installed on the server, we need Grunt, now. Grunt will automate tasks for us like compiling SASS when they change or keeping track of and moving JavaScript libraries to standardized directories.


npm install -g grunt-cli

Grunt has many plugins available to monitor various tasks. There are a few we need for this project.


npm install grunt --save-dev
npm install grunt-sass --save-dev
npm install grunt-contrib-watch --save-dev
npm install grunt-contrib-copy --save-dev

These plugins watch the SASS files for changes and recompile them when they do change. The last one copies various assets from the bower_components folder into the directories where they are easier to work with and reference. The –save-dev option tells Node that this dependency is only included in the development environment.

Finally, we need a Gruntfile.js which will define our grunt configuration and tell grunt what to do when the task runner is started.


module.exports = function (grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        // Copy web assets from bower_components to more convenient directories.
        copy: {
            main: {
                files: [
                    // Vendor scripts.
                    {
                        expand: true,
                        cwd: 'bower_components/bootstrap-sass/assets/javascripts/',
                        src: ['**/*.js'],
                        dest: 'scripts/bootstrap-sass/'
                    },
                    {
                        expand: true,
                        cwd: 'bower_components/jquery/dist/',
                        src: ['**/*.js', '**/*.map'],
                        dest: 'scripts/jquery/'
                    },

                    // Fonts.
                    {
                        expand: true,
                        filter: 'isFile',
                        flatten: true,
                        cwd: 'bower_components/',
                        src: ['bootstrap-sass/assets/fonts/**'],
                        dest: 'fonts/'
                    },

                    // Stylesheets
                    {
                        expand: true,
                        cwd: 'bower_components/bootstrap-sass/assets/stylesheets/',
                        src: ['**/*.scss'],
                        dest: 'scss/'
                    }
                ]
            },
        },

        // Compile SASS files into minified CSS.
        sass: {
            options: {
                includePaths: ['bower_components/bootstrap-sass/assets/stylesheets']
            },
            dist: {
                options: {
                    outputStyle: 'compressed'
                },
                files: {
                    'css/app.css': 'scss/app.scss'
                }
            }
        },

        // Watch these files and notify of changes.
        watch: {
            grunt: { files: ['Gruntfile.js'] },

            sass: {
                files: [
                    'scss/**/*.scss'
                ],
                tasks: ['sass']
            }
        }
    });

    // Load externally defined tasks. 
    grunt.loadNpmTasks('grunt-sass');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-copy');

    // Establish tasks we can run from the terminal.
    grunt.registerTask('build', ['sass', 'copy']);
    grunt.registerTask('default', ['build', 'watch']);
}

Add a scss folder to the project and put the file app.scss inside it. This file needs one line in it to import the bootstrap framework. When you add your own SCSS components, they should be imported via this file, also.


@import 'bootstrap.css';

Run Grunt, and as you develop, your changes will be automagically compiled, compressed and managed on the server.


grunt

vagrant@local /var/www $ cd bootstraptest
vagrant@local /var/www/bootstraptest (master *+=) $ ls
bower_components/  bower.json*  Gruntfile.js*  LICENSE*  node_modules/  package.json*  README.md*  scss/
vagrant@local /var/www/bootstraptest (master *+=) $ grunt
Running "sass:dist" (sass) task

Running "copy:main" (copy) task
Copied 101 files

Running "watch" task
Waiting...
>> File "Gruntfile.js" changed.
Completed in 0.001s at Sat Sep 17 2016 15:24:08 GMT+0000 (UTC) - Waiting...

Add an index.html file to the document root, and voila! Development can now commence.

After the framework is set up for development, it’s a snap to create an ajax enabled form and do something on a web page.

You could write a php file that generates a list of prime numbers and a form that asks the user how many prime numbers to generate, for example.

https://github.com/jnodwell/bootstraptest

Drupal on nginx

After moving from apache to nginx, you might notice no matter what link you try to go to, you get what appears to be your home page. More than likely, clean urls are enabled and your .conf file isn’t set up to route them properly (since .htaccess rules are not used on nginx).

For D6

location / {


    root  /var/www/webroot/docroot;
    try_files $uri @rewrite; 
     autoindex off;
    index  index.html index.htm index.php;


  } 

  location @rewrite {
      rewrite ^/(.*)$ /index.php?q=$1;
}

For D8

location / {


    root  /var/www/webroot/docroot;
    try_files $uri $uri/ /index.php$query_string;
     autoindex off;
    index  index.html index.htm index.php;


  }

Reference
A more complete sample conf file with all the blocks defined, see here.

Drupal on nginx

server {
    server_name example.com;
    root /var/www/drupal8; ## <-- Your only path reference.

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Very rarely should these ever be accessed outside of your lan
    location ~* \.(txt|log)$ {
        allow 192.168.0.0/16;
        deny all;
    }

    location ~ \..*/.*\.php$ {
        return 403;
    }

    location ~ ^/sites/.*/private/ {
        return 403;
    }

    # Allow "Well-Known URIs" as per RFC 5785
    location ~* ^/.well-known/ {
        allow all;
    }

    # Block access to "hidden" files and directories whose names begin with a
    # period. This includes directories used by version control systems such
    # as Subversion or Git to store control files.
    location ~ (^|/)\. {
        return 403;
    }

    location / {
        # try_files $uri @rewrite; # For Drupal <= 6
        try_files $uri /index.php?$query_string; # For Drupal >= 7
    }

    location @rewrite {
        rewrite ^/(.*)$ /index.php?q=$1;
    }

    # Don't allow direct access to PHP files in the vendor directory.
    location ~ /vendor/.*\.php$ {
        deny all;
        return 404;
    }

    # In Drupal 8, we must also match new paths where the '.php' appears in
    # the middle, such as update.php/selection. The rule we use is strict,
    # and only allows this pattern with the update.php front controller.
    # This allows legacy path aliases in the form of
    # blog/index.php/legacy-path to continue to route to Drupal nodes. If
    # you do not have any paths like that, then you might prefer to use a
    # laxer rule, such as:
    #   location ~ \.php(/|$) {
    # The laxer rule will continue to work if Drupal uses this new URL
    # pattern with front controllers other than update.php in a future
    # release.
    location ~ '\.php$|^/update.php' {
        fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
        # Security note: If you're running a version of PHP older than the
        # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.
        # See http://serverfault.com/q/627903/94922 for details.
        include fastcgi_params;
        # Block httpoxy attacks. See https://httpoxy.org/.
        fastcgi_param HTTP_PROXY "";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_intercept_errors on;
        # PHP 5 socket location.
        #fastcgi_pass unix:/var/run/php5-fpm.sock;
        # PHP 7 socket location.
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    }

    # Fighting with Styles? This little gem is amazing.
    # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
    location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7
        try_files $uri @rewrite;
    }

    # Handle private files through Drupal.
    location ~ ^/system/files/ { # For Drupal >= 7
        try_files $uri /index.php?$query_string;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }
}