From fb70e3b1769e9d008b75585e7c3fdfa061491f4d Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Wed, 17 May 2017 00:00:56 +0900
Subject: [PATCH] Refactoring

---
 gulpfile.ts                         |   5 +-
 webpack.config.ts                   | 120 ----------------------------
 webpack/langs.ts                    |  23 ++++++
 webpack/module/index.ts             |   5 ++
 webpack/module/rules/i18n.ts        |  34 ++++++++
 webpack/module/rules/index.ts       |  11 +++
 webpack/module/rules/stylus.ts      |  13 +++
 webpack/module/rules/tag.ts         |  20 +++++
 webpack/module/rules/theme-color.ts |  25 ++++++
 webpack/plugins/const.ts            |  13 +++
 webpack/plugins/index.ts            |  19 +++++
 webpack/webpack.config.ts           |  35 ++++++++
 12 files changed, 202 insertions(+), 121 deletions(-)
 delete mode 100644 webpack.config.ts
 create mode 100644 webpack/langs.ts
 create mode 100644 webpack/module/index.ts
 create mode 100644 webpack/module/rules/i18n.ts
 create mode 100644 webpack/module/rules/index.ts
 create mode 100644 webpack/module/rules/stylus.ts
 create mode 100644 webpack/module/rules/tag.ts
 create mode 100644 webpack/module/rules/theme-color.ts
 create mode 100644 webpack/plugins/const.ts
 create mode 100644 webpack/plugins/index.ts
 create mode 100644 webpack/webpack.config.ts

diff --git a/gulpfile.ts b/gulpfile.ts
index 6591a7d69d..906a48fcc9 100644
--- a/gulpfile.ts
+++ b/gulpfile.ts
@@ -132,8 +132,11 @@ gulp.task('build:client', [
 ]);
 
 gulp.task('webpack', done => {
-	const output = childProcess.execSync(Path.join('.', 'node_modules', '.bin', 'webpack') + ' --config webpack.config.ts', );
+	const output = childProcess.execSync(
+		Path.join('.', 'node_modules', '.bin', 'webpack') + ' --config ./webpack/webpack.config.ts');
+
 	console.log(output.toString());
+
 	done();
 });
 
diff --git a/webpack.config.ts b/webpack.config.ts
deleted file mode 100644
index e550a00222..0000000000
--- a/webpack.config.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * webpack config
- */
-
-import * as fs from 'fs';
-import * as webpack from 'webpack';
-const StringReplacePlugin = require('string-replace-webpack-plugin');
-import * as yaml from 'js-yaml';
-
-import version from './src/version';
-const constants = require('./src/const.json');
-
-const languages = {
-	'en': yaml.safeLoad(fs.readFileSync('./locales/en.yml', 'utf-8')),
-	'ja': yaml.safeLoad(fs.readFileSync('./locales/ja.yml', 'utf-8'))
-};
-
-const native = languages.ja;
-
-const env = process.env.NODE_ENV;
-const isProduction = env === 'production';
-
-module.exports = (Object as any).entries(languages).map(([lang, locale]) => {
-	locale = Object.assign({}, native, locale);
-
-	const pack /*: webpack.Configuration ← fuck wrong type definition!!! */ = {
-		name: lang,
-		entry: {
-			'desktop': './src/web/app/desktop/script.js',
-			'mobile': './src/web/app/mobile/script.js',
-			'dev': './src/web/app/dev/script.js',
-			'auth': './src/web/app/auth/script.js'
-		},
-		module: {
-			rules: [
-				{
-					enforce: 'pre',
-					test: /\.(tag|js)$/,
-					exclude: /node_modules/,
-					loader: StringReplacePlugin.replace({
-						replacements: [
-							{
-								pattern: /%i18n:(.+?)%/g, replacement: (_, key) => {
-									let text = locale;
-									const error = key.split('.').some(k => {
-										if (text.hasOwnProperty(k)) {
-											text = text[k];
-											return false;
-										} else {
-											return true;
-										}
-									});
-									if (error) {
-										console.warn(`key '${key}' not found in '${lang}'`);
-										return key;
-									} else {
-										return text.replace(/'/g, '\\\'').replace(/"/g, '\\"');
-									}
-								}
-							}
-						]
-					})
-				},
-				{
-					enforce: 'pre',
-					test: /\.tag$/,
-					exclude: /node_modules/,
-					loader: StringReplacePlugin.replace({
-						replacements: [
-							{ pattern: /\$theme\-color\-foreground/g, replacement: () => constants.themeColorForeground },
-							{ pattern: /\$theme\-color/g, replacement: () => constants.themeColor },
-						]
-					})
-				},
-				{
-					test: /\.tag$/,
-					exclude: /node_modules/,
-					loader: 'riot-tag-loader',
-					query: {
-						hot: false,
-						style: 'stylus',
-						expr: false,
-						compact: true,
-						parserOptions: {
-							style: {
-								compress: true
-							}
-						}
-					}
-				},
-				{
-					test: /\.styl$/,
-					exclude: /node_modules/,
-					use: [
-						{ loader: 'style-loader' },
-						{ loader: 'css-loader' },
-						{ loader: 'stylus-loader' }
-					]
-				}
-			]
-		},
-		plugins: [
-			new webpack.DefinePlugin({
-				VERSION: JSON.stringify(version),
-				THEME_COLOR: JSON.stringify(constants.themeColor)
-			}),
-			new StringReplacePlugin()
-		],
-		output: {
-			path: __dirname + '/built/web/assets',
-			filename: `[name].${version}.${lang}.js`
-		}
-	};
-
-	if (isProduction) {
-		//pack.plugins.push(new webpack.optimize.UglifyJsPlugin());
-	}
-
-	return pack;
-});
diff --git a/webpack/langs.ts b/webpack/langs.ts
new file mode 100644
index 0000000000..409b25504a
--- /dev/null
+++ b/webpack/langs.ts
@@ -0,0 +1,23 @@
+/**
+ * Languages Loader
+ */
+
+import * as fs from 'fs';
+import * as yaml from 'js-yaml';
+
+const loadLang = lang => yaml.safeLoad(
+	fs.readFileSync(`./locales/${lang}.yml`, 'utf-8'));
+
+const native = loadLang('ja');
+
+const langs = Object.entries({
+	'en': loadLang('en'),
+	'ja': native
+});
+
+langs.map(([, locale]) => {
+	// Extend native language (Japanese)
+	locale = Object.assign({}, native, locale);
+});
+
+export default langs;
diff --git a/webpack/module/index.ts b/webpack/module/index.ts
new file mode 100644
index 0000000000..15f36557ce
--- /dev/null
+++ b/webpack/module/index.ts
@@ -0,0 +1,5 @@
+import rules from './rules';
+
+export default (lang, locale) => ({
+	rules: rules(lang, locale)
+});
diff --git a/webpack/module/rules/i18n.ts b/webpack/module/rules/i18n.ts
new file mode 100644
index 0000000000..0539e97db4
--- /dev/null
+++ b/webpack/module/rules/i18n.ts
@@ -0,0 +1,34 @@
+/**
+ * Replace i18n texts
+ */
+
+const StringReplacePlugin = require('string-replace-webpack-plugin');
+
+export default (lang, locale) => ({
+	enforce: 'pre',
+	test: /\.(tag|js)$/,
+	exclude: /node_modules/,
+	loader: StringReplacePlugin.replace({
+		replacements: [
+			{
+				pattern: /%i18n:(.+?)%/g, replacement: (_, key) => {
+					let text = locale;
+					const error = key.split('.').some(k => {
+						if (text.hasOwnProperty(k)) {
+							text = text[k];
+							return false;
+						} else {
+							return true;
+						}
+					});
+					if (error) {
+						console.warn(`key '${key}' not found in '${lang}'`);
+						return key;
+					} else {
+						return text.replace(/'/g, '\\\'').replace(/"/g, '\\"');
+					}
+				}
+			}
+		]
+	})
+});
diff --git a/webpack/module/rules/index.ts b/webpack/module/rules/index.ts
new file mode 100644
index 0000000000..2308f4e535
--- /dev/null
+++ b/webpack/module/rules/index.ts
@@ -0,0 +1,11 @@
+import i18n from './i18n';
+import themeColor from './theme-color';
+import tag from './tag';
+import stylus from './stylus';
+
+export default (lang, locale) => [
+	i18n(lang, locale),
+	themeColor(),
+	tag(),
+	stylus()
+];
diff --git a/webpack/module/rules/stylus.ts b/webpack/module/rules/stylus.ts
new file mode 100644
index 0000000000..dd1e4c3218
--- /dev/null
+++ b/webpack/module/rules/stylus.ts
@@ -0,0 +1,13 @@
+/**
+ * Stylus support
+ */
+
+export default () => ({
+	test: /\.styl$/,
+	exclude: /node_modules/,
+	use: [
+		{ loader: 'style-loader' },
+		{ loader: 'css-loader' },
+		{ loader: 'stylus-loader' }
+	]
+});
diff --git a/webpack/module/rules/tag.ts b/webpack/module/rules/tag.ts
new file mode 100644
index 0000000000..706af35b40
--- /dev/null
+++ b/webpack/module/rules/tag.ts
@@ -0,0 +1,20 @@
+/**
+ * Riot tags
+ */
+
+export default () => ({
+	test: /\.tag$/,
+	exclude: /node_modules/,
+	loader: 'riot-tag-loader',
+	query: {
+		hot: false,
+		style: 'stylus',
+		expr: false,
+		compact: true,
+		parserOptions: {
+			style: {
+				compress: true
+			}
+		}
+	}
+});
diff --git a/webpack/module/rules/theme-color.ts b/webpack/module/rules/theme-color.ts
new file mode 100644
index 0000000000..7ee545191c
--- /dev/null
+++ b/webpack/module/rules/theme-color.ts
@@ -0,0 +1,25 @@
+/**
+ * Theme color provider
+ */
+
+const StringReplacePlugin = require('string-replace-webpack-plugin');
+
+const constants = require('../../../src/const.json');
+
+export default () => ({
+	enforce: 'pre',
+	test: /\.tag$/,
+	exclude: /node_modules/,
+	loader: StringReplacePlugin.replace({
+		replacements: [
+			{
+				pattern: /\$theme\-color\-foreground/g,
+				replacement: () => constants.themeColorForeground
+			},
+			{
+				pattern: /\$theme\-color/g,
+				replacement: () => constants.themeColor
+			},
+		]
+	})
+});
diff --git a/webpack/plugins/const.ts b/webpack/plugins/const.ts
new file mode 100644
index 0000000000..ccfcb45260
--- /dev/null
+++ b/webpack/plugins/const.ts
@@ -0,0 +1,13 @@
+/**
+ * Constant Replacer
+ */
+
+import * as webpack from 'webpack';
+
+import version from '../../src/version';
+const constants = require('../../src/const.json');
+
+export default () => new webpack.DefinePlugin({
+	VERSION: JSON.stringify(version),
+	THEME_COLOR: JSON.stringify(constants.themeColor)
+});
diff --git a/webpack/plugins/index.ts b/webpack/plugins/index.ts
new file mode 100644
index 0000000000..0692b9f8dd
--- /dev/null
+++ b/webpack/plugins/index.ts
@@ -0,0 +1,19 @@
+const StringReplacePlugin = require('string-replace-webpack-plugin');
+
+import constant from './const';
+
+const env = process.env.NODE_ENV;
+const isProduction = env === 'production';
+
+export default () => {
+	const plugins = [
+		constant(),
+		new StringReplacePlugin()
+	];
+
+	if (isProduction) {
+		//plugins.push(new webpack.optimize.UglifyJsPlugin());
+	}
+
+	return plugins;
+};
diff --git a/webpack/webpack.config.ts b/webpack/webpack.config.ts
new file mode 100644
index 0000000000..50733a6cff
--- /dev/null
+++ b/webpack/webpack.config.ts
@@ -0,0 +1,35 @@
+/**
+ * webpack configuration
+ */
+
+import module_ from './module';
+import plugins from './plugins';
+
+import langs from './langs';
+import version from '../src/version';
+
+module.exports = langs.map(([lang, locale]) => {
+	// Chunk name
+	const name = lang;
+
+	// Entries
+	const entry = {
+		'desktop': './src/web/app/desktop/script.js',
+		'mobile': './src/web/app/mobile/script.js',
+		'dev': './src/web/app/dev/script.js',
+		'auth': './src/web/app/auth/script.js'
+	};
+
+	const output = {
+		path: __dirname + '/../built/web/assets',
+		filename: `[name].${version}.${lang}.js`
+	};
+
+	return {
+		name,
+		entry,
+		module: module_(lang, locale),
+		plugins: plugins(),
+		output
+	};
+});