Skip to content

Instantly share code, notes, and snippets.

@domjtalbot
Created January 19, 2017 13:06
Show Gist options
  • Save domjtalbot/1a003cb008fec25049706e795b543c06 to your computer and use it in GitHub Desktop.
Save domjtalbot/1a003cb008fec25049706e795b543c06 to your computer and use it in GitHub Desktop.
Webpack build integrated with C# MVC.net - Useful for access to Webpack build hash for generating asset urls
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
@Html.Partial("_WebpackManifest")
</head>
<body class="">
@Html.Partial("_WebpackScripts")
</body>
</html>
@using Test.Models;
@{
var webpack = new Webpack(){};
}
@if (!string.IsNullOrEmpty(webpack.manifest))
{
@:<script> window.webpackManifest = @Html.Raw(webpack.manifest)</script>
}
@using Test.Models;
@{
var webpack = new Webpack(){};
}
<script src="@webpack.common"></script>
<script src="@webpack.vendor"></script>
<script src="@webpack.app"></script>
import fs, { writeFile, readFileSync } from 'fs';
import { resolve, join } from 'path';
import CleanWebpackPlugin from 'clean-webpack-plugin';
import webpack, { optimize, DefinePlugin, LoaderOptionsPlugin } from 'webpack';
import ChunkManifestPlugin from 'chunk-manifest-webpack-plugin';
import SplitByPath from 'webpack-split-by-path';
import WebpackMd5Hash from 'webpack-md5-hash';
import WebpackShellPlugin from 'webpack-shell-plugin';
import BellOnBundlerErrorPlugin from 'bell-on-bundler-error-plugin';
import NpmInstall from 'npm-install-webpack-plugin';
import ProgressBar from 'progress-bar-webpack-plugin';
import { green, yellow, underline } from 'chalk';
import Ora from 'ora';
import merge from 'deepmerge';
import './scripts/env.es6';
import { Debug } from './scripts/debug.es6';
import devConfig from './webpack.client.development.config';
import prodConfig from './webpack.client.production.config';
import requireAlias, { extDep } from './scripts/requirejsConfig';
const debug = new Debug('webpack:config');
const NODE_ENV = process.env.NODE_ENV;
const node_envString = green(`${NODE_ENV} webpack build`);
debug(underline(node_envString));
/**
* Load .babelrc and override where necessary
* Webpack Tree shaking requires ES6 modules enabled.
*/
const babelrcFile = readFileSync('.babelrc');
const babelrcJson = JSON.parse(babelrcFile);
const babelrc = {
...babelrcJson,
babelrc: false,
};
babelrc.presets.forEach((preset, index) => {
if (preset[0] === 'es2015') {
babelrc.presets[index][1].modules = false;
return;
}
});
if (NODE_ENV === 'development') {
babelrc.plugins.push('react-hot-loader/babel');
}
debug(`${yellow.bold('.babelrc =')} ${yellow(JSON.stringify(babelrc))}`);
/**
* Webpack settings shared for all ENV
* @type {Object}
*/
const config = {
context: __dirname,
entry: {
heapp: './scripts/heapp.js',
},
resolve: {
extensions: [
'.js',
'.scss',
'.sass',
'.css',
'.jsx',
'.es6',
],
alias: {
...requireAlias,
modernizr$: resolve(__dirname, 'config/.modernizrrc'),
},
modules: ['node_modules', 'scripts', 'assets/scss'],
},
externals: {
...extDep,
},
module: {
loaders: [
{
enforce: 'pre',
test: /\.es6$/,
exclude: [
resolve(__dirname, 'node_modules'),
resolve(__dirname, 'scripts/dist'),
resolve(__dirname, 'scripts/ext-lib'),
],
loader: 'eslint',
query: {
configFile: 'config/eslint-config-es6.yml',
failOnError: false,
failOnWarning: false,
emitError: false,
emitWarning: false,
fix: true,
quiet: true,
},
},
{
test: /\.[js|jsx]$/,
exclude: [
resolve(__dirname, 'node_modules'),
resolve(__dirname, 'scripts/ext-lib'),
],
loader: 'babel',
query: babelrc,
},
{
test: /\.modernizrrc$/,
exclude: 'node_modules',
loader: 'modernizr',
},
],
},
plugins: [
new SplitByPath ([
{
name: 'vendor',
path: [
join(__dirname, 'node_modules'),
join(__dirname, 'scripts/ext-lib'),
]
},
], {
manifest: 'common',
}),
new DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(NODE_ENV),
},
}),
new LoaderOptionsPlugin({
minimize: true,
}),
new CleanWebpackPlugin([
'bin/webpack.json',
'bin/assets',
], {
root: __dirname,
}),
new WebpackMd5Hash(),
new optimize.OccurrenceOrderPlugin(),
new WebpackShellPlugin({
onBuildStart: [],
onBuildEnd: [],
}),
new NpmInstall({
dev: false,
peerDependencies: true,
}),
new ProgressBar({
format: `:╢:bar╟ :percent :eta`,
incomplete: '░',
complete: green('░'),
}),
function() {
this.plugin('done', stats => {
const spinner = new Ora('Exporting webpack stats to json file');
const filePath = resolve(__dirname, 'bin/webpack.json');
const statsJson = stats.toJson();
statsJson.node_env = NODE_ENV;
const data = JSON.stringify(statsJson);
spinner.start();
writeFile(filePath, data, err => {
if (err) {
spinner.fail();
throw err;
}
spinner.succeed();
});
});
},
],
};
const envConfig = (NODE_ENV === 'production') ? prodConfig : devConfig;
const webpackConfig = merge(config, envConfig);
webpackConfig.plugins = [
...config.plugins,
...envConfig.plugins,
];
export { webpackConfig as default }
import { join } from 'path';
import { LoaderOptionsPlugin } from 'webpack';
/**
* Webpack settings required for development ENV
* @type {Object}
* @exports Object Webpack development config
*/
export default {
devtool: 'source-map',
devServer: {
'content-base': 'scripts/dist',
inline: true,
'history-api-fallback': true,
https: false,
host: '0.0.0.0',
port: 5001,
compress: true,
colors: true,
hot: true,
},
output: {
filename: '[name].js',
chunkFilename: '[name].js',
path: join(__dirname, 'scripts/dist'),
publicPath: '//localhost:5001/scripts/dist/',
},
plugins: [
new LoaderOptionsPlugin({
minimize: true,
}),
],
};
import { resolve } from 'path';
import webpack, { optimize } from 'webpack';
import ManifestPlugin from 'webpack-manifest-plugin';
/**
* Webpack settings required for Production ENV
* @type {Object}
* @exports Object Webpack production config
*/
export default {
output: {
filename: '[name].[hash].js',
chunkFilename: '[name].[chunkhash].js',
path: './public/assets/[hash]',
publicPath: '/public/assets/[hash]/',
},
plugins: [
new ManifestPlugin({
fileName: 'manifest.json',
}),
/*new optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
comments: false,
}),*/
new optimize.DedupePlugin(),
],
};
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
namespace Test.Models
{
public class Webpack
{
/// <summary>
/// Initializes a new instance of <see cref="Webpack"/> class
/// </summary>
/// <remarks>Webpack constructor</remarks>
public Webpack()
{
this.Folder = "~/bin/";
this.Name = "webpack";
this.Extension = ".json";
string webpackStatsFile = File.ReadAllText(Path);
this.json = JsonConvert.DeserializeObject<WebpackJson>(webpackStatsFile);
}
/// <summary>
/// Folder containing webpack json
/// </summary>
/// <value>The folder property gets/sets the folder path</value>
public string Folder { get; set; }
/// <summary>
/// Filename
/// </summary>
/// <value>The Name property gets/sets the name of requested icon.</value>
public string Name { get; set; }
/// <summary>
/// Extension used by webpack stats file
/// </summary>
/// <value>The Extension property gets/sets the extension used by the webpack stats file</value>
public string Extension { get; set; }
/// <summary>
/// The full path to the webpack stats file
/// </summary>
/// <value>The Path property gets the full file path</value>
private string Path
{
get
{
var path = Folder + Name + Extension;
return HttpContext.Current.Server.MapPath(path);
}
}
public new WebpackJson json { get; set; }
public string app
{
get
{
return json.publicPath + json.assetsByChunkName.app[0];
}
}
public string common
{
get
{
return json.publicPath + json.assetsByChunkName.common[0];
}
}
public string vendor
{
get
{
return json.publicPath + json.assetsByChunkName.vendor[0];
}
}
public string node_env
{
get
{
return json.node_env;
}
}
public string manifest
{
get
{
if (node_env != "production")
{
return "{}";
}
string manifestPath = json.publicPath + "manifest.json";
string serverPath = HttpContext.Current.Server.MapPath(manifestPath);
string manifest = File.ReadAllText(serverPath);
return manifest;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Test.Models
{
public class WebpackJson
{
public object[] errors { get; set; }
public object[] warnings { get; set; }
public string version { get; set; }
public string hash { get; set; }
public int time { get; set; }
public string publicPath { get; set; }
public Assetsbychunkname assetsByChunkName { get; set; }
public Asset[] assets { get; set; }
public Entrypoints entrypoints { get; set; }
public Chunk[] chunks { get; set; }
public Module[] modules { get; set; }
public int filteredModules { get; set; }
public object[] children { get; set; }
public string node_env { get; set; }
public class Assetsbychunkname
{
public string[] app { get; set; }
public string[] common { get; set; }
public string[] vendor { get; set; }
}
public class Entrypoints
{
public App app { get; set; }
}
public class App
{
public int[] chunks { get; set; }
public string[] assets { get; set; }
}
public class Asset
{
public string name { get; set; }
public int size { get; set; }
public int?[] chunks { get; set; }
public string[] chunkNames { get; set; }
public bool emitted { get; set; }
}
public class Chunk
{
public int id { get; set; }
public bool rendered { get; set; }
public bool initial { get; set; }
public bool entry { get; set; }
public bool extraAsync { get; set; }
public int size { get; set; }
public string[] names { get; set; }
public string[] files { get; set; }
public string hash { get; set; }
public int?[] parents { get; set; }
public string loc { get; set; }
public Origin[] origins { get; set; }
}
public class Origin
{
public int moduleId { get; set; }
public string module { get; set; }
public string moduleIdentifier { get; set; }
public string moduleName { get; set; }
public string loc { get; set; }
public string name { get; set; }
public string[] reasons { get; set; }
}
public class Module
{
public int id { get; set; }
public string identifier { get; set; }
public string name { get; set; }
public int index { get; set; }
public int index2 { get; set; }
public int size { get; set; }
public bool cacheable { get; set; }
public bool built { get; set; }
public bool optional { get; set; }
public bool prefetched { get; set; }
public int?[] chunks { get; set; }
public object[] assets { get; set; }
public string issuer { get; set; }
public int? issuerId { get; set; }
public string issuerName { get; set; }
public bool failed { get; set; }
public int errors { get; set; }
public int warnings { get; set; }
public Reason[] reasons { get; set; }
public bool usedExports { get; set; }
public object providedExports { get; set; }
public string source { get; set; }
}
public class Reason
{
public int moduleId { get; set; }
public string moduleIdentifier { get; set; }
public string module { get; set; }
public string moduleName { get; set; }
public string type { get; set; }
public object userRequest { get; set; }
public string loc { get; set; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment