webpack.config.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. const webpack = require('webpack');
  2. const cssnano = require('cssnano');
  3. const pxtorem = require('postcss-pxtorem');
  4. const HtmlWebpackPlugin = require('html-webpack-plugin');
  5. const CleanWebpackPlugin = require('clean-webpack-plugin');
  6. const ExtractTextPlugin = require('extract-text-webpack-plugin');
  7. const debug = require('debug')('app:webpack:config');
  8. const fs = require('fs');
  9. const config = require('../config');
  10. const paths = config.utils_paths;
  11. const { __DEV__, __PROD__ } = config.globals;
  12. function getPublicPath(path) {
  13. const publicPath =
  14. config.publicPath.substr(config.publicPath.length - 2, 1) === '/' ? config.publicPath : config.publicPath + '/';
  15. if (path) {
  16. path = path.indexOf('/') === 0 ? path.substr(1, path.length - 1) : path;
  17. return publicPath + path;
  18. } else {
  19. return publicPath;
  20. }
  21. }
  22. function fileNameFormat(type, ext) {
  23. ext = ext || '[ext]';
  24. return `src/[name].[${type}].${ext}`;
  25. }
  26. debug('Creating configuration.');
  27. const webpackConfig = {
  28. name: 'client',
  29. target: 'web',
  30. cache: true,
  31. resolve: {
  32. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  33. alias: {
  34. '@src': paths.client(),
  35. '@project': paths.project(),
  36. '@components': paths.components(),
  37. },
  38. },
  39. module: {},
  40. stats: config.compiler_stats,
  41. };
  42. if (config.compiler_devtool) webpackConfig.devtool = config.compiler_devtool;
  43. const APP_ENTRY = paths.client('main.js');
  44. const devApp = [
  45. 'webpack/hot/dev-server',
  46. `webpack-hot-middleware/client?path=${config.publicPath}__webpack_hmr`,
  47. 'react-hot-loader/patch',
  48. APP_ENTRY,
  49. ];
  50. webpackConfig.entry = {
  51. app: __DEV__ ? devApp : [APP_ENTRY],
  52. };
  53. webpackConfig.output = {
  54. filename: fileNameFormat(config.compiler_hash_type, 'js'),
  55. path: paths.dist(),
  56. publicPath: getPublicPath(),
  57. chunkFilename: fileNameFormat(config.compiler_hash_type, 'js'),
  58. };
  59. function getLibPath(path) {
  60. let pach = null;
  61. try {
  62. fs.readdirSync(path).forEach(file => {
  63. if (file.indexOf('lib') === 0) {
  64. pach = file;
  65. }
  66. });
  67. } catch (e) {
  68. console.log(e);
  69. }
  70. return pach;
  71. }
  72. if (!config.css) config.css = [];
  73. for (let i = 0; i < config.css.length; i += 1) {
  74. const script = config.css[i];
  75. if (script.indexOf('http') !== 0) {
  76. config.css[i] = getPublicPath(script);
  77. }
  78. }
  79. if (!config.scripts) config.scripts = [];
  80. for (let i = 0; i < config.scripts.length; i += 1) {
  81. const script = config.scripts[i];
  82. if (script.indexOf('http') !== 0) {
  83. config.scripts[i] = getPublicPath(script);
  84. }
  85. }
  86. config.scripts.push(getPublicPath(getLibPath(paths.lib())));
  87. webpackConfig.plugins = [
  88. new webpack.DefinePlugin(config.globals),
  89. new CleanWebpackPlugin(['*'], {
  90. root: paths.dist(),
  91. }),
  92. new webpack.ProgressPlugin(),
  93. new webpack.DllReferencePlugin({
  94. context: paths.lib(),
  95. manifest: paths.lib('manifest.json'),
  96. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  97. }),
  98. new HtmlWebpackPlugin({
  99. template: paths.client('index.html'),
  100. hash: false,
  101. minify: {
  102. collapseWhitespace: true,
  103. },
  104. title: config.title,
  105. filename: 'index.html',
  106. inject: 'body',
  107. globals: Object.assign(config.globals, {
  108. keyword: config.keyword,
  109. description: config.description,
  110. scripts: config.scripts,
  111. css: config.css,
  112. }),
  113. }),
  114. new webpack.LoaderOptionsPlugin({
  115. options: {
  116. postcss() {
  117. return [
  118. cssnano({
  119. autoprefixer: {
  120. add: true,
  121. browsers: ['iOS >= 7', 'Android >= 4.1'],
  122. },
  123. discardComments: {
  124. removeAll: true,
  125. },
  126. discardUnused: false,
  127. mergeIdents: false,
  128. reduceIdents: false,
  129. safe: true,
  130. sourcemap: true,
  131. }),
  132. pxtorem({
  133. rootValue: 50,
  134. propWhiteList: [],
  135. }),
  136. ];
  137. },
  138. },
  139. }),
  140. ];
  141. if (__DEV__) {
  142. webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin());
  143. } else {
  144. webpackConfig.plugins.push(
  145. // new webpack.optimize.CommonsChunkPlugin({
  146. // name: ['app'],
  147. // minChunks: function (module, count) {
  148. // return module.context && module.context.indexOf('node_modules') !== -1
  149. // }
  150. // }),
  151. new webpack.optimize.UglifyJsPlugin({
  152. cache: true,
  153. parallel: true,
  154. }),
  155. new ExtractTextPlugin({
  156. filename: fileNameFormat(config.compiler_hash_type, 'css'),
  157. allChunks: true,
  158. }),
  159. );
  160. }
  161. webpackConfig.module.rules = [
  162. {
  163. test: /\.(js|jsx)$/,
  164. exclude: /node_modules/,
  165. use: ['babel-loader', 'eslint-loader'],
  166. },
  167. {
  168. test: /\.yml$/,
  169. use: ['json-loader', 'yaml-loader'],
  170. },
  171. {
  172. test: /\.json$/,
  173. use: 'json-loader',
  174. },
  175. {
  176. test: /\.(svg)(\?.*)?$/,
  177. include: paths.client(),
  178. use: {
  179. loader: 'url-loader',
  180. options: {
  181. limit: 10240,
  182. name: fileNameFormat('hash'),
  183. },
  184. },
  185. },
  186. {
  187. test: /\.(png|jpe?g|gif)(\?.*)?$/,
  188. use: {
  189. loader: 'url-loader',
  190. options: {
  191. limit: 10240,
  192. name: fileNameFormat('hash'),
  193. },
  194. },
  195. },
  196. {
  197. test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
  198. use: {
  199. loader: 'url-loader',
  200. options: {
  201. limit: 10240,
  202. name: fileNameFormat('hash'),
  203. },
  204. },
  205. },
  206. ];
  207. function loaderAnalysis(loaders) {
  208. if (__PROD__) {
  209. return ExtractTextPlugin.extract({
  210. fallback: loaders.shift(),
  211. use: loaders,
  212. });
  213. }
  214. return loaders;
  215. }
  216. const theme = {
  217. // 'primary-color': '#8573AD',
  218. 'brand-primary': '#6b43fe',
  219. };
  220. webpackConfig.module.rules.push({
  221. test: /\.css$/,
  222. use: loaderAnalysis(['style-loader', 'css-loader', 'postcss-loader']),
  223. });
  224. webpackConfig.module.rules.push({
  225. test: /\.less$/,
  226. use: loaderAnalysis([
  227. 'style-loader',
  228. 'css-loader',
  229. 'postcss-loader',
  230. `less-loader?{'modifyVars':${JSON.stringify(theme)}}`,
  231. ]),
  232. });
  233. module.exports = webpackConfig;