Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Webpack and Gulp with multiple entry points to transpile app and test directories?

I am building a basic blog project to practice using React, ES6, and Mocha test framework. I'm having trouble transpiling my ES6 tests and app code within my default Gulp task.

I get this error when I run the default task and change the contents of ./test/posts.js for the watch to take effect:

[11:17:29] Using gulpfile ~/WebstormProjects/blog/gulpfile.js
[11:17:29] Starting 'default'...
[11:17:29] Finished 'default' after 8.54 ms

stream.js:75
      throw er; // Unhandled stream error in pipe.
      ^
Error: invalid argument
    at pathToArray (/Users/christian/WebstormProjects/blog/node_modules/memory-fs/lib/MemoryFileSystem.js:44:10)
    at MemoryFileSystem.mkdirpSync (/Users/christian/WebstormProjects/blog/node_modules/memory-fs/lib/MemoryFileSystem.js:139:13)
    at MemoryFileSystem.(anonymous function) [as mkdirp] (/Users/christian/WebstormProjects/blog/node_modules/memory-fs/lib/MemoryFileSystem.js:279:34)
    at Compiler.<anonymous> (/Users/christian/WebstormProjects/blog/node_modules/webpack/lib/Compiler.js:229:25)
    at Compiler.applyPluginsAsync (/Users/christian/WebstormProjects/blog/node_modules/tapable/lib/Tapable.js:60:69)
    at Compiler.emitAssets (/Users/christian/WebstormProjects/blog/node_modules/webpack/lib/Compiler.js:226:7)
    at Watching.<anonymous> (/Users/christian/WebstormProjects/blog/node_modules/webpack/lib/Compiler.js:54:18)
    at /Users/christian/WebstormProjects/blog/node_modules/webpack/lib/Compiler.js:403:12
    at Compiler.next (/Users/christian/WebstormProjects/blog/node_modules/tapable/lib/Tapable.js:67:11)
    at Compiler.<anonymous> (/Users/christian/WebstormProjects/blog/node_modules/webpack/lib/CachePlugin.js:40:4)

Process finished with exit code 1

webpack.config.js

var path = require('path');
var babel = require('babel-loader');

module.exports = {
  entry: {
    app: './app/js/blog.js',
    test: './test/posts.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: './build',
    sourceMapFilename: '[name].bundle.map'
  },
  watch: true,
  devtool: '#sourcemap',
  module: {
    loaders: [
      {
        loader: 'babel',
        test: /\.jsx?$/,
        exclude: /(node_modules|bower_components)/,
        query: {
          presets: ['react', 'es2015']
        }
      }
    ],
    resolve: {
      root: path.resolve('./app'),
      extensions: ['', '.js']
    }
  }
};

gulpfile.js

var gulp = require('gulp');
var webpack = require('webpack-stream');
var watch = require('gulp-watch');
var babel = require('babel-loader');
var named = require('vinyl-named');


gulp.task('default', function() {
  watch(['./app/**/*.js', './test/*.js'], function() {
    return gulp.src(['./app/js/blog.js', './test/posts.js'])
      .pipe(named())
      .pipe(webpack(require('./webpack.config.js')))
      .pipe(gulp.dest('./build'));
  });
});

gulp.task('testBundle', function() {
  gulp.src('./test/posts.js')
    .pipe(webpack(require('./webpack.config.js')))
    .pipe(gulp.dest('./build'));
});

posts.js

import expect from 'expect'
import { post, posts, addPost } from '../app/js/blog'
import { createStore } from 'redux'

describe('Blog', () => {

  describe('posts', () => {

    it('should be able to create a post', () => {
      let store = createStore(posts);
      store.dispatch(addPost('First Post', 'Blah blah blah'))
      let blah = { id: 'First Post', content: 'Blah blah blah'}
      expect(store.getState()).toEqual(blah)
    });

    it('should be able to create multiple posts', () => {
      let store2 = createStore(posts);
      store2.dispatch(addPost('Second Post', 'Shh'))
      let expectedState1 = { id: 'Second Post', content: 'Shh' }
      expect(store2.getState()).toEqual(expectedState1)

      store2.dispatch(addPost('Third Post', 'Whatever'))
      let expectedState2 = { id: 'Third Post', content: 'Whatever'}
      expect(store2.getState()).toEqual(expectedState2)
    })
  });
});

Ultimately, I'd like the transpiled code to be found at ./build/blog.bundle.js and ./build/posts.bundle.js for ./app/js/blog.js and ./test/posts.js, respectively.

like image 418
Christian Avatar asked Mar 19 '16 18:03

Christian


1 Answers

There were some issues with my webpack.config.js and gulpfile.js. Apparently, the path property within the output object in webpack.config.js was conflicting with gulp.dest('./build'). I also reformatted some things in the config file to mirror a working one. Below is the code that should work. Hopefully this helps others trying to accomplish the same thing.

I have gulp starting webpack to produce separate bundle files for app and test entry points. I also get sourcemaps for each of the bundles that are created. Now I can write tests and app code in ES6 and run them with Mocha within WebStorm!

gulpfile.js

var gulp = require('gulp');
var webpack = require('webpack-stream');
var watch = require('gulp-watch');

gulp.task('default', function() {
  watch(['./app/**/*.js', './test/*.js'], function() {
    return gulp.src(['./app/js/blog.js', './test/posts.js'])
      .pipe(named())
      .pipe(webpack(require('./webpack.config.js')))
      .pipe(gulp.dest('./build'));
  });
});

gulp.task('webpack', function() {
  return gulp.src(['./app/js/blog.js', './test/posts.js'])
    .pipe(named())
    .pipe(webpack(require('./webpack.config.js')))
    .pipe(gulp.dest('./build'));
});

webpack.config.js

var path = require('path');
var babel = require('babel-loader');

module.exports = {
  entry: {
    app: './app/js/entry.js',
    test: './test/posts.js'
  },
  output: {
    filename: '[name].bundle.js',
    sourceMapFilename: '[name].bundle.map'
  },
  devtool: '#source-map',
  module: {
    loaders: [
      {
        loader: 'babel',
        test: /\.jsx?$/,
        exclude: /(node_modules|bower_components)/,
        query: {
          presets: ['react', 'es2015']
        }
      }
    ]
  },
  resolve: {
    root: path.resolve('./app'),
    extensions: ['', '.js']
  }
};

entry.js

import { posts } from './blog'

import { createStore } from 'redux'

createStore(posts)

blog.js

const posts = (state = [], action) => {
  switch (action.type) {
    case 'ADD_POST':
      return post(undefined, action)
    default:
      return state
  }
}

const post = (state = {}, action) => {
  switch (action.type) {
    case 'ADD_POST':
      return { id: action.name, content: action.content }
  }
}

// action creator
const addPost = (name, content) => {
  return {
    type: 'ADD_POST',
    name,
    content
  }
}

export { posts, post, addPost }
like image 188
Christian Avatar answered Sep 18 '22 04:09

Christian