diff --git a/package.json b/package.json
index 906d512dc1..bf924dcdb0 100644
--- a/package.json
+++ b/package.json
@@ -117,6 +117,7 @@
 		"gulp-typescript": "3.2.4",
 		"gulp-uglify": "3.0.0",
 		"gulp-util": "3.0.8",
+		"hard-source-webpack-plugin": "^0.5.18",
 		"highlight.js": "9.12.0",
 		"html-minifier": "^3.5.9",
 		"inquirer": "5.0.1",
@@ -145,6 +146,7 @@
 		"recaptcha-promise": "0.1.3",
 		"reconnecting-websocket": "3.2.2",
 		"redis": "2.8.0",
+		"replace-string-loader": "0.0.7",
 		"request": "2.83.0",
 		"rimraf": "2.6.2",
 		"riot": "3.8.1",
diff --git a/webpack/module/rules/base64.ts b/webpack/module/rules/base64.ts
index 6d7eaddeba..886f0e8b38 100644
--- a/webpack/module/rules/base64.ts
+++ b/webpack/module/rules/base64.ts
@@ -3,17 +3,18 @@
  */
 
 import * as fs from 'fs';
-const StringReplacePlugin = require('string-replace-webpack-plugin');
 
 export default () => ({
 	enforce: 'pre',
 	test: /\.(vue|js)$/,
 	exclude: /node_modules/,
-	loader: StringReplacePlugin.replace({
-		replacements: [{
-			pattern: /%base64:(.+?)%/g, replacement: (_, key) => {
+	use: [{
+		loader: 'replace-string-loader',
+		options: {
+			search: /%base64:(.+?)%/g,
+			replace: (_, key) => {
 				return fs.readFileSync(__dirname + '/../../../src/web/' + key, 'base64');
 			}
-		}]
-	})
+		}
+	}]
 });
diff --git a/webpack/module/rules/fa.ts b/webpack/module/rules/fa.ts
index 2679089239..56ca19d4b4 100644
--- a/webpack/module/rules/fa.ts
+++ b/webpack/module/rules/fa.ts
@@ -2,16 +2,17 @@
  * Replace fontawesome symbols
  */
 
-const StringReplacePlugin = require('string-replace-webpack-plugin');
 import { pattern, replacement } from '../../../src/common/build/fa';
 
 export default () => ({
 	enforce: 'pre',
 	test: /\.(vue|js|ts)$/,
 	exclude: /node_modules/,
-	loader: StringReplacePlugin.replace({
-		replacements: [{
-			pattern, replacement
-		}]
-	})
+	use: [{
+		loader: 'replace-string-loader',
+		options: {
+			search: pattern,
+			replace: replacement
+		}
+	}]
 });
diff --git a/webpack/module/rules/i18n.ts b/webpack/module/rules/i18n.ts
index f8063a311f..1bd771f43b 100644
--- a/webpack/module/rules/i18n.ts
+++ b/webpack/module/rules/i18n.ts
@@ -2,7 +2,6 @@
  * Replace i18n texts
  */
 
-const StringReplacePlugin = require('string-replace-webpack-plugin');
 import Replacer from '../../../src/common/build/i18n';
 
 export default lang => {
@@ -12,10 +11,12 @@ export default lang => {
 		enforce: 'pre',
 		test: /\.(vue|js|ts)$/,
 		exclude: /node_modules/,
-		loader: StringReplacePlugin.replace({
-			replacements: [{
-				pattern: replacer.pattern, replacement: replacer.replacement
-			}]
-		})
+		use: [{
+			loader: 'replace-string-loader',
+			options: {
+				search: replacer.pattern,
+				replace: replacer.replacement
+			}
+		}]
 	};
 };
diff --git a/webpack/module/rules/index.ts b/webpack/module/rules/index.ts
index c63da7112d..c4442b06cd 100644
--- a/webpack/module/rules/index.ts
+++ b/webpack/module/rules/index.ts
@@ -1,7 +1,6 @@
 import i18n from './i18n';
-import license from './license';
 import fa from './fa';
-import base64 from './base64';
+//import base64 from './base64';
 import themeColor from './theme-color';
 import vue from './vue';
 import stylus from './stylus';
@@ -11,9 +10,8 @@ import collapseSpaces from './collapse-spaces';
 export default lang => [
 	collapseSpaces(),
 	i18n(lang),
-	license(),
 	fa(),
-	base64(),
+	//base64(),
 	themeColor(),
 	vue(),
 	stylus(),
diff --git a/webpack/module/rules/license.ts b/webpack/module/rules/license.ts
deleted file mode 100644
index e3aaefa2bf..0000000000
--- a/webpack/module/rules/license.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Inject license
- */
-
-const StringReplacePlugin = require('string-replace-webpack-plugin');
-import { licenseHtml } from '../../../src/common/build/license';
-
-export default () => ({
-	enforce: 'pre',
-	test: /\.(vue|js)$/,
-	exclude: /node_modules/,
-	loader: StringReplacePlugin.replace({
-		replacements: [{
-			pattern: '%license%', replacement: () => licenseHtml
-		}]
-	})
-});
diff --git a/webpack/module/rules/theme-color.ts b/webpack/module/rules/theme-color.ts
index a65338465a..14f5457bf3 100644
--- a/webpack/module/rules/theme-color.ts
+++ b/webpack/module/rules/theme-color.ts
@@ -2,24 +2,24 @@
  * Theme color provider
  */
 
-const StringReplacePlugin = require('string-replace-webpack-plugin');
-
 const constants = require('../../../src/const.json');
 
 export default () => ({
 	enforce: 'pre',
 	test: /\.vue$/,
 	exclude: /node_modules/,
-	loader: StringReplacePlugin.replace({
-		replacements: [
-			{
-				pattern: /\$theme\-color\-foreground/g,
-				replacement: () => constants.themeColorForeground
-			},
-			{
-				pattern: /\$theme\-color/g,
-				replacement: () => constants.themeColor
-			},
-		]
-	})
+	use: [/*{
+		loader: 'replace-string-loader',
+		options: {
+			search: /\$theme\-color\-foreground/g,
+			replace: constants.themeColorForeground
+		}
+	}, */{
+		loader: 'replace-string-loader',
+		options: {
+			search: '$theme-color',
+			replace: constants.themeColor,
+			flags: 'g'
+		}
+	}]
 });
diff --git a/webpack/module/rules/typescript.ts b/webpack/module/rules/typescript.ts
index 2c94137318..5f2903d77e 100644
--- a/webpack/module/rules/typescript.ts
+++ b/webpack/module/rules/typescript.ts
@@ -4,6 +4,7 @@
 
 export default () => ({
 	test: /\.ts$/,
+	exclude: /node_modules/,
 	loader: 'ts-loader',
 	options: {
 		configFile: __dirname + '/../../../src/web/app/tsconfig.json',
diff --git a/webpack/plugins/banner.ts b/webpack/plugins/banner.ts
deleted file mode 100644
index a8774e0a39..0000000000
--- a/webpack/plugins/banner.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import * as os from 'os';
-import * as webpack from 'webpack';
-
-export default version => new webpack.BannerPlugin({
-	banner:
-		`Misskey v${version} | MIT Licensed, (c) syuilo 2014-2018\n` +
-		'https://github.com/syuilo/misskey\n' +
-		`built by ${os.hostname()} at ${new Date()}\n` +
-		'hash:[hash], chunkhash:[chunkhash]'
-});
diff --git a/webpack/plugins/consts.ts b/webpack/plugins/consts.ts
index 16a5691622..a01c18af6f 100644
--- a/webpack/plugins/consts.ts
+++ b/webpack/plugins/consts.ts
@@ -7,6 +7,7 @@ import * as webpack from 'webpack';
 import version from '../../src/version';
 const constants = require('../../src/const.json');
 import config from '../../src/conf';
+import { licenseHtml } from '../../src/common/build/license';
 
 export default lang => {
 	const consts = {
@@ -24,6 +25,7 @@ export default lang => {
 		_LANG_: lang,
 		_HOST_: config.host,
 		_URL_: config.url,
+		_LICENSE_: licenseHtml
 	};
 
 	const _consts = {};
@@ -32,7 +34,5 @@ export default lang => {
 		_consts[key] = JSON.stringify(consts[key]);
 	});
 
-	return new webpack.DefinePlugin(Object.assign({}, _consts, {
-		__CONSTS__: JSON.stringify(consts)
-	}));
+	return new webpack.DefinePlugin(_consts);
 };
diff --git a/webpack/plugins/index.ts b/webpack/plugins/index.ts
index d97f781558..a29d2b7e2f 100644
--- a/webpack/plugins/index.ts
+++ b/webpack/plugins/index.ts
@@ -1,17 +1,16 @@
-const StringReplacePlugin = require('string-replace-webpack-plugin');
+const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
 
 import consts from './consts';
 import hoist from './hoist';
 import minify from './minify';
-import banner from './banner';
 
 const env = process.env.NODE_ENV;
 const isProduction = env === 'production';
 
 export default (version, lang) => {
 	const plugins = [
-		consts(lang),
-		new StringReplacePlugin()
+		new HardSourceWebpackPlugin(),
+		consts(lang)
 	];
 
 	if (isProduction) {
@@ -19,7 +18,5 @@ export default (version, lang) => {
 		plugins.push(minify());
 	}
 
-	plugins.push(banner(version));
-
 	return plugins;
 };
diff --git a/webpack/webpack.config.ts b/webpack/webpack.config.ts
index 1a516d1419..f4b9247e63 100644
--- a/webpack/webpack.config.ts
+++ b/webpack/webpack.config.ts
@@ -40,6 +40,9 @@ module.exports = Object.keys(langs).map(lang => {
 				'.js', '.ts'
 			]
 		},
-		cache: true
+		cache: true,
+		devtool: 'eval',
+		stats: true,
+		profile: true
 	};
 });