webpack.config.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. for (let i = 0; i < config.scripts.length; i += 1) {
  73. const script = config.scripts[i];
  74. if (script.indexOf('http') !== 0) {
  75. config.scripts[i] = getPublicPath(script);
  76. }
  77. }
  78. config.scripts.push(getPublicPath(getLibPath(paths.lib())));
  79. webpackConfig.plugins = [
  80. new webpack.DefinePlugin(config.globals),
  81. new CleanWebpackPlugin(['*'], {
  82. root: paths.dist(),
  83. }),
  84. new webpack.ProgressPlugin(),
  85. new webpack.DllReferencePlugin({
  86. context: paths.lib(),
  87. manifest: paths.lib('manifest.json'),
  88. extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
  89. }),
  90. new HtmlWebpackPlugin({
  91. template: paths.client('index.html'),
  92. hash: false,
  93. minify: {
  94. collapseWhitespace: true,
  95. },
  96. title: config.title,
  97. filename: 'index.html',
  98. inject: 'body',
  99. globals: Object.assign(config.globals, {
  100. keyword: config.keyword,
  101. description: config.description,
  102. scripts: config.scripts,
  103. }),
  104. }),
  105. new webpack.LoaderOptionsPlugin({
  106. options: {
  107. postcss() {
  108. return [
  109. cssnano({
  110. autoprefixer: {
  111. add: true,
  112. browsers: ['iOS >= 7', 'Android >= 4.1'],
  113. },
  114. discardComments: {
  115. removeAll: true,
  116. },
  117. discardUnused: false,
  118. mergeIdents: false,
  119. reduceIdents: false,
  120. safe: true,
  121. sourcemap: true,
  122. }),
  123. pxtorem({
  124. rootValue: 50,
  125. propWhiteList: [],
  126. }),
  127. ];
  128. },
  129. },
  130. }),
  131. ];
  132. if (__DEV__) {
  133. webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin());
  134. } else {
  135. webpackConfig.plugins.push(
  136. // new webpack.optimize.CommonsChunkPlugin({
  137. // name: ['app'],
  138. // minChunks: function (module, count) {
  139. // return module.context && module.context.indexOf('node_modules') !== -1
  140. // }
  141. // }),
  142. new webpack.optimize.UglifyJsPlugin({
  143. cache: true,
  144. parallel: true,
  145. }),
  146. new ExtractTextPlugin({
  147. filename: fileNameFormat(config.compiler_hash_type, 'css'),
  148. allChunks: true,
  149. }),
  150. );
  151. }
  152. webpackConfig.module.rules = [
  153. {
  154. test: /\.(js|jsx)$/,
  155. exclude: /node_modules/,
  156. use: ['babel-loader', 'eslint-loader'],
  157. },
  158. {
  159. test: /\.yml$/,
  160. use: ['json-loader', 'yaml-loader'],
  161. },
  162. {
  163. test: /\.json$/,
  164. use: 'json-loader',
  165. },
  166. {
  167. test: /\.(svg)(\?.*)?$/,
  168. include: paths.client(),
  169. use: {
  170. loader: 'url-loader',
  171. options: {
  172. limit: 10240,
  173. name: fileNameFormat('hash'),
  174. },
  175. },
  176. },
  177. {
  178. test: /\.(png|jpe?g|gif)(\?.*)?$/,
  179. use: {
  180. loader: 'url-loader',
  181. options: {
  182. limit: 10240,
  183. name: fileNameFormat('hash'),
  184. },
  185. },
  186. },
  187. {
  188. test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
  189. use: {
  190. loader: 'url-loader',
  191. options: {
  192. limit: 10240,
  193. name: fileNameFormat('hash'),
  194. },
  195. },
  196. },
  197. ];
  198. function loaderAnalysis(loaders) {
  199. if (__PROD__) {
  200. return ExtractTextPlugin.extract({
  201. fallback: loaders.shift(),
  202. use: loaders,
  203. });
  204. }
  205. return loaders;
  206. }
  207. const theme = {
  208. // 'primary-color': '#8573AD',
  209. 'brand-primary': '#6b43fe',
  210. };
  211. webpackConfig.module.rules.push({
  212. test: /\.css$/,
  213. use: loaderAnalysis(['style-loader', 'css-loader', 'postcss-loader']),
  214. });
  215. webpackConfig.module.rules.push({
  216. test: /\.less$/,
  217. use: loaderAnalysis([
  218. 'style-loader',
  219. 'css-loader',
  220. 'postcss-loader',
  221. `less-loader?{'modifyVars':${JSON.stringify(theme)}}`,
  222. ]),
  223. });
  224. module.exports = webpackConfig;