17

I've got a Wordpress/MySQL docker container, which I use for developing themes & plugins. I access this on localhost:8000.

It uses a Gulp build process & I am trying to add browsersync to the mix. I'm having a hard time getting the browsersync to actually proxy out of the container. From the Gulp output I can see that its generating the changes, just not actually making any changes in the browser.

Heres my docker-compose.yml, gulpfile, dockerfile & shell script.

version: '2'

services:
    wordpress_db:
        image: mariadb
        restart: 'always'
        ports:
            - 3360:3306
        volumes:
            - ./db_data:/docker-entrypoint-initdb.d
        environment:
            MYSQL_ROOT_PASSWORD: wordpress
            MYSQL_DATABASE: wordpress

    wordpress:
        depends_on:
            - wordpress_db
        image: wordpress
        restart: 'always'
        environment:
            WORDPRESS_DB_NAME: wordpress
            WORDPRESS_DB_USER: root
            WORDPRESS_DB_PASSWORD: wordpress
        ports:
            - 8000:3000
        volumes:
            - ./uploads:/var/www/html/wp-content/uploads
            - ./plugins:/var/www/html/wp-content/plugins
            - ./theme:/var/www/html/wp-content/themes/theme
        links:
            - wordpress_db:mysql

    composer:
        image: composer/composer:php7
        depends_on:
            - wordpress
        restart: 'no'
        environment:
            ACF_PRO_KEY: this_would_be_my_ACF_pro_key_:)
        volumes_from:
            - wordpress
        working_dir: /var/www/html/wp-content/themes/theme
        command: install

    node:
        restart: 'no'
        image: node:slim
        depends_on:
            - wordpress
        volumes_from:
            - wordpress
        working_dir: /var/www/html/wp-content/themes/theme
        build:
            context: .
            dockerfile: WordpressBuild
            args:
                - SITE_VERSION=0.0.1
var browserSync  = require('browser-sync');
var reload      = browserSync.reload;
var watchify     = require('watchify');
var browserify   = require('browserify');
var source       = require('vinyl-source-stream');
var buffer       = require('vinyl-buffer');
var gulp         = require('gulp');
var gutil        = require('gulp-util');
var gulpSequence = require('gulp-sequence');
var processhtml  = require('gulp-minify-html');
var sass         = require('gulp-sass');
var autoprefixer = require('gulp-autoprefixer');
var watch        = require('gulp-watch');
var cleanCSS    = require('gulp-clean-css');
var uglify       = require('gulp-uglify');
var streamify    = require('gulp-streamify');
var sourcemaps   = require('gulp-sourcemaps');
var concat       = require('gulp-concat');
var babel        = require('gulp-babel');
var fontawesome  = require('node-font-awesome');
var prod         = gutil.env.prod;

var onError = function(err) {
  console.log(err.message);
  this.emit('end');
};

// bundling js with browserify and watchify
var b = watchify(browserify('./src/js/app', {
  cache: {},
  packageCache: {},
  fullPaths: true
}));

gulp.task('js', bundle);
b.on('update', bundle);
b.on('log', gutil.log);

function bundle() {
  return b.bundle()
    .on('error', onError)
    .pipe(source('app.js'))
    .pipe(buffer())
    .pipe(sourcemaps.init())
    .pipe(prod ? babel({
      presets: ['es2015']
    }) : gutil.noop())
    .pipe(concat('app.js'))
    .pipe(!prod ? sourcemaps.write('.') : gutil.noop())
    .pipe(prod ? streamify(uglify()) : gutil.noop())
    .pipe(gulp.dest('./assets/js'))
    .pipe(browserSync.stream());
}

// fonts
gulp.task('fonts', function() {
  gulp.src(fontawesome.fonts)
    .pipe(gulp.dest('./assets/fonts'));
});

// sass
gulp.task('sass', function() {
  return gulp.src('./src/scss/**/*.scss')
    .pipe(sourcemaps.init())
      .pipe(sass({
        includePaths: [].concat(require('node-bourbon').includePaths, ['node_modules/foundation-sites/scss', 'node_modules/motion-ui/src', fontawesome.scssPath])
      }))
      .on('error', onError)
      .pipe(prod ? cleanCSS() : gutil.noop())
      .pipe(prod ? autoprefixer({
        browsers: ['last 2 versions'],
        cascade: false
      }) : gutil.noop())
    .pipe(!prod ? sourcemaps.write('.') : gutil.noop())
    .pipe(gulp.dest('./assets/css'))
    .pipe(browserSync.stream());
});

gulp.task('watch', function(){
  gulp.watch('./src/scss/**/*.scss', ['sass']);
  gulp.watch('./src/js/**/*.js', ['js']);
});

// browser-sync task for starting the server.
gulp.task('serve', function() {
    //watch files
    var files = [
    './assets/css/*.scss',
    './*.php'
    ];

    //initialize browsersync
    browserSync.init(files, {
    //browsersync with a php server
    proxy: "localhost",
    notify: false
  });
  gulp.watch('./src/scss/**/*.scss', ['sass']);

    // gulp.task('default', gulpSequence(['fonts', 'sass', 'js', 'watch']));
});

// use gulp-sequence to finish building html, sass and js before first page load
gulp.task('default', gulpSequence(['fonts', 'sass', 'js'], 'serve'));

The docker-compose.yml refers to the following dockerfile:

FROM node

# Grab our version variable from the yml file
ARG SITE_VERSION

# Install gulp globally
RUN npm install -g gulp node-gyp node-sass

# Install dependencies
COPY ./gulp-build.sh /
RUN chmod 777 /gulp-build.sh
ENTRYPOINT ["/gulp-build.sh"]
CMD ["run"]

which installs gulp and node-sass, and also copies the following gulp-guild.sh script into the container:

#!/bin/bash

cd /var/www/html/wp-content/themes/theme
# npm rebuild node-sass && npm install && gulp --dev
npm rebuild node-sass && npm install && gulp
Matheus Avellar
  • 1,411
  • 1
  • 22
  • 29
Chris J Allen
  • 18,148
  • 20
  • 71
  • 109
  • Is the `gulp` process running in one of your services (in a container), or is it running natively? – jkinkead Mar 01 '17 at 19:33
  • its running within the container. There's a dockerfile, which copys a gulp-build.sh script into the container. I've updated my post to reflect this. – Chris J Allen Mar 01 '17 at 21:23
  • I'm not familiar with browsersync, so I can't give a complete answer, but the `proxy: 'localhost'` setting in your gulpfile won't work. You'll likely need to expose the port browsersync runs on in the `node` service, and configure browsersync to talk to the wordpress service (`proxy: 'wordpress:8000'`). Then you'd point your browser at the exposed port on the `node` service instead of the wordpress port. – jkinkead Mar 01 '17 at 23:57
  • Progress! Exposing the node port 3001 gives me access to the UI now on localhost:3001. I've tried setting wordpress:8000 and localhost:8000 in the gulpfile proxy setting, but no joy accessing the server end. I'm guessing its not proxying as it should. Not 100% clear on how the actual request cycle works when proxying. – Chris J Allen Mar 02 '17 at 08:20
  • Sorry, within a container, you access other services on their internal ports. Try `wordpress:3000`. – jkinkead Mar 02 '17 at 18:52
  • Thats done the trick: https://gist.github.com/chrisjimallen/b628355c32eb96ad2d8945188cb5799f :) If you are able to post an answer I can award the bounty. Thanks! – Chris J Allen Mar 03 '17 at 18:37
  • Done! Glad I could help. :) – jkinkead Mar 03 '17 at 20:23
  • @ChrisJAllen I realize this is an older thread, but I'm wondering if you would you be willing to share your full docker-wp-browsersync config, say via a git repo? I'm trying to get something similar going, and have tried to use the bits from files mentioned in your original question, but haven't been able to get it all working. I'd be curious to see the full file structure with dockerfile, docker-compose, etc. settings. Thanks much for any assistance here! – nickpish Apr 26 '19 at 05:53
  • @nickpish I can't find it :( I've been through my git repos and I remember it was saved on an old attlassian account which i cant access anymore. I will search my backup drive later to see if its on there anywhere. I must confess I have since moved the local by flywheel, as most of my stuff these days is wordpress. – Chris J Allen May 02 '19 at 09:58
  • @ChrisJAllen No problem- thanks so much for looking! While I realize I should avoid extended conversations in comments, I must ask- do you prefer using the flywheel setup for local WP dev over the Docker rig? – nickpish May 02 '19 at 17:03
  • Absolutely yes. I think it uses docker under the hood, but takes all the configuration out of the equation. Comes with mail hog and sequel pro integration out the box too. – Chris J Allen May 03 '19 at 23:42
  • @ChrisJAllen Awesome- thanks; that's good to know. Maybe I'll make the switch as well. – nickpish May 07 '19 at 19:37
  • @nickpish, been toying with the idea of a blog post about how i use it. You reckon that'd be useful? – Chris J Allen May 08 '19 at 20:13
  • @ChrisJAllen Definitely! Please ping me if you end up posting an article. – nickpish May 09 '19 at 19:23
  • 1
    @nickpish https://chrisjallen.com/2019/05/10/my-simple-wordpress-development-workflow/ ;) – Chris J Allen May 10 '19 at 20:11
  • @ChrisJAllen Fantastic!! Much appreciated! – nickpish May 12 '19 at 19:20

1 Answers1

20

The primary problem with your configuration is that you're pointing to localhost in the gulpfile. This points to the local container, not your host machine, so browsersync won't be able to connect to Wordpress.

You first need to update the gulpfile to point to the wordpress service, on its internal port:

browserSync.init(files, {
    // The hostname is the name of your service in docker-compose.yml.
    // The port is what's defined in your Dockerfile.
    proxy: "wordpress:3000",
    notify: false,
    // Do not open browser on start
    open: false
})

Then you need to add a port mapping to expose the browsersync server from your node service. In your docker-compose.yml file:

node:
    ports:
        - "3000:3000"
        - "3001:3001"

You should now be able to access the browsersync proxy on localhost:3001.

P.S. In case you have more than one site serving in one ngninx docker container, you can edit nginx config file for specific site in /etc/nginx/conf.d/somesite.conf and add new line: listen: 3000;

Alex
  • 87
  • 1
  • 4
jkinkead
  • 3,477
  • 16
  • 31
  • I'll also throw in here that `WordpressBuild` refers to a parallel file named `WordpressBuild` which, as explained [here](https://derickbailey.com/2017/03/09/selecting-a-node-js-image-for-docker/) would contain a node version such as `FROM node:6.10.0`. – MikeiLL Aug 22 '17 at 16:22