diff --git Gruntfile.js Gruntfile.js
index c7e7f73b2b..ba02c875c6 100644
--- Gruntfile.js
+++ Gruntfile.js
@@ -1,24 +1,18 @@
 /* jshint node:true */
+const webpackConfig = require( './webpack.config' );
+
 module.exports = function(grunt) {
 	var path = require('path'),
 		fs = require( 'fs' ),
 		SOURCE_DIR = 'src/',
 		BUILD_DIR = 'build/',
-		autoprefixer = require('autoprefixer'),
-		mediaConfig = {},
-		mediaBuilds = ['audiovideo', 'grid', 'models', 'views'];
+		autoprefixer = require( 'autoprefixer' );
 
 	// Load tasks.
 	require('matchdep').filterDev(['grunt-*', '!grunt-legacy-util']).forEach( grunt.loadNpmTasks );
 	// Load legacy utils
 	grunt.util = require('grunt-legacy-util');
 
-	mediaBuilds.forEach( function ( build ) {
-		var path = SOURCE_DIR + 'wp-includes/js/media';
-		mediaConfig[ build ] = { files : {} };
-		mediaConfig[ build ].files[ path + '-' + build + '.js' ] = [ path + '/' + build + '.manifest.js' ];
-	} );
-
 	// Project configuration.
 	grunt.initConfig({
 		postcss: {
@@ -157,7 +151,6 @@ module.exports = function(grunt) {
 				}
 			}
 		},
-		browserify: mediaConfig,
 		sass: {
 			colors: {
 				expand: true,
@@ -318,9 +311,6 @@ module.exports = function(grunt) {
 				]
 			},
 			media: {
-				options: {
-					browserify: true
-				},
 				src: [
 					SOURCE_DIR + 'wp-includes/js/media/**/*.js'
 				]
@@ -531,7 +521,13 @@ module.exports = function(grunt) {
 				dest: SOURCE_DIR + 'wp-includes/js/jquery/jquery.masonry.min.js'
 			}
 		},
-
+		webpack: {
+			options: {
+				stats: ! process.env.NODE_ENV || process.env.NODE_ENV === 'development'
+			},
+				prod: webpackConfig,
+				dev: Object.assign( { watch: true }, webpackConfig)
+		},
 		concat: {
 			tinymce: {
 				options: {
@@ -661,6 +657,9 @@ module.exports = function(grunt) {
 
 	// Register tasks.
 
+	// Webpack tash.
+	grunt.loadNpmTasks( 'grunt-webpack' );
+
 	// RTL task.
 	grunt.registerTask('rtl', ['rtlcss:core', 'rtlcss:colors']);
 
@@ -684,15 +683,9 @@ module.exports = function(grunt) {
 	grunt.renameTask( 'watch', '_watch' );
 
 	grunt.registerTask( 'watch', function() {
-		if ( ! this.args.length || this.args.indexOf( 'browserify' ) > -1 ) {
-			grunt.config( 'browserify.options', {
-				browserifyOptions: {
-					debug: true
-				},
-				watch: true
-			} );
+		if ( ! this.args.length || this.args.indexOf( 'webpack' ) > -1 ) {
 
-			grunt.task.run( 'browserify' );
+			grunt.task.run( 'webpack' );
 		}
 
 		grunt.task.run( '_' + this.nameArgs );
@@ -703,7 +696,7 @@ module.exports = function(grunt) {
 	] );
 
 	grunt.registerTask( 'precommit:js', [
-		'browserify',
+		'webpack',
 		'jshint:corejs',
 		'uglify:bookmarklet',
 		'uglify:masonry',
@@ -860,7 +853,7 @@ module.exports = function(grunt) {
 	grunt.event.on('watch', function( action, filepath, target ) {
 		var src;
 
-		if ( [ 'all', 'rtl', 'browserify' ].indexOf( target ) === -1 ) {
+		if ( [ 'all', 'rtl', 'webpack' ].indexOf( target ) === -1 ) {
 			return;
 		}
 
diff --git package.json package.json
index 047d5fc35d..3516101ac2 100644
--- package.json
+++ package.json
@@ -33,5 +33,10 @@
     "grunt-rtlcss": "~2.0.1",
     "grunt-sass": "~1.2.1",
     "matchdep": "~1.0.0"
+  },
+  "dependencies": {
+    "grunt-webpack": "^3.0.0",
+    "webpack": "^2.6.1",
+    "webpack-dev-server": "^2.5.0"
   }
 }
diff --git webpack.config.js webpack.config.js
new file mode 100644
index 0000000000..d503a39abf
--- /dev/null
+++ webpack.config.js
@@ -0,0 +1,21 @@
+var path         = require('path'),
+	SOURCE_DIR   = 'src/',
+	mediaConfig  = {},
+	mediaBuilds  = ['audiovideo', 'grid', 'models', 'views'];
+
+
+mediaBuilds.forEach( function ( build ) {
+	var path = SOURCE_DIR + 'wp-includes/js/media';
+	mediaConfig[ build ] = './' + path + '/' + build + '.manifest.js';
+} );
+
+module.exports = {
+	entry: mediaConfig,
+	output: {
+		path:     path.join( __dirname, 'src/wp-includes/js' ),
+		filename: 'media-[name].js'
+	},
+
+	cache: true,
+
+}
