webpack.config.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. const path = require('path');
  2. const webpack = require('webpack');
  3. const CopyPlugin = require('copy-webpack-plugin');
  4. const ManifestPlugin = require('webpack-manifest-plugin');
  5. const VersionPlugin = require('./build/version_plugin');
  6. const ExtractTextPlugin = require('extract-text-webpack-plugin');
  7. const webJsOptions = {
  8. babelrc: false,
  9. presets: [['env', { modules: false }], 'stage-2'],
  10. // yo-yoify converts html template strings to direct dom api calls
  11. plugins: ['yo-yoify']
  12. };
  13. const serviceWorker = {
  14. target: 'webworker',
  15. entry: {
  16. serviceWorker: './app/serviceWorker.js'
  17. },
  18. output: {
  19. filename: '[name].js',
  20. path: path.resolve(__dirname, 'dist'),
  21. publicPath: '/'
  22. }
  23. };
  24. const web = {
  25. target: 'web',
  26. entry: {
  27. // babel-polyfill and fluent are directly included in vendor
  28. // because they are not explicitly referenced by app
  29. vendor: ['babel-polyfill', 'fluent'],
  30. app: ['./app/main.js']
  31. },
  32. output: {
  33. filename: '[name].[hash:8].js',
  34. path: path.resolve(__dirname, 'dist'),
  35. publicPath: '/'
  36. },
  37. module: {
  38. rules: [
  39. {
  40. test: /\.js$/,
  41. oneOf: [
  42. {
  43. include: [require.resolve('./assets/cryptofill')],
  44. use: [
  45. {
  46. loader: 'file-loader',
  47. options: {
  48. name: '[name].[hash:8].[ext]'
  49. }
  50. }
  51. ]
  52. },
  53. {
  54. // fluent gets exposed as a global so that each language script
  55. // can load independently and share it.
  56. include: [path.dirname(require.resolve('fluent'))],
  57. use: [
  58. {
  59. loader: 'expose-loader',
  60. options: 'fluent'
  61. },
  62. {
  63. loader: 'babel-loader',
  64. options: {
  65. presets: [['env', { modules: false }], 'stage-3']
  66. }
  67. }
  68. ]
  69. },
  70. {
  71. loader: 'babel-loader',
  72. include: [
  73. path.resolve(__dirname, 'app'),
  74. path.resolve(__dirname, 'common'),
  75. // some dependencies need to get re-babeled because we
  76. // have different targets than their default configs
  77. path.resolve(__dirname, 'node_modules/testpilot-ga/src'),
  78. path.resolve(__dirname, 'node_modules/fluent-intl-polyfill'),
  79. path.resolve(__dirname, 'node_modules/intl-pluralrules')
  80. ],
  81. options: webJsOptions
  82. },
  83. {
  84. // Strip asserts from our deps, mainly choojs family
  85. include: [path.resolve(__dirname, 'node_modules')],
  86. loader: 'webpack-unassert-loader'
  87. }
  88. ]
  89. },
  90. {
  91. test: /\.(png|jpg)$/,
  92. loader: 'file-loader',
  93. options: {
  94. name: '[name].[hash:8].[ext]'
  95. }
  96. },
  97. {
  98. test: /\.svg$/,
  99. use: [
  100. {
  101. loader: 'file-loader',
  102. options: {
  103. name: '[name].[hash:8].[ext]'
  104. }
  105. },
  106. {
  107. loader: 'svgo-loader',
  108. options: {
  109. plugins: [
  110. { removeViewBox: false }, // true causes stretched images
  111. { convertStyleToAttrs: true }, // for CSP, no unsafe-eval
  112. { removeTitle: true } // for smallness
  113. ]
  114. }
  115. }
  116. ]
  117. },
  118. {
  119. // creates style.css with all styles
  120. test: /\.css$/,
  121. use: ExtractTextPlugin.extract({
  122. use: [
  123. {
  124. loader: 'css-loader',
  125. options: {
  126. importLoaders: 1
  127. }
  128. },
  129. 'postcss-loader'
  130. ]
  131. })
  132. },
  133. {
  134. // creates a js script for each ftl
  135. test: /\.ftl$/,
  136. use: [
  137. {
  138. loader: 'file-loader',
  139. options: {
  140. name: '[path][name].[hash:8].js'
  141. }
  142. },
  143. 'extract-loader',
  144. 'babel-loader',
  145. './build/fluent_loader'
  146. ]
  147. },
  148. {
  149. // creates test.js for /test
  150. test: require.resolve('./test/frontend/index.js'),
  151. use: ['babel-loader', 'val-loader']
  152. },
  153. {
  154. // loads all assets from assets/ for use by common/assets.js
  155. test: require.resolve('./build/generate_asset_map.js'),
  156. use: ['babel-loader', 'val-loader']
  157. },
  158. {
  159. // loads all the ftl from public/locales for use by common/locales.js
  160. test: require.resolve('./build/generate_l10n_map.js'),
  161. use: ['babel-loader', 'val-loader']
  162. }
  163. ]
  164. },
  165. plugins: [
  166. new CopyPlugin([
  167. {
  168. context: 'public',
  169. from: '*.*'
  170. }
  171. ]),
  172. new webpack.IgnorePlugin(/dist/), // used in common/*.js
  173. new webpack.IgnorePlugin(/require-from-string/), // used in common/locales.js
  174. new webpack.HashedModuleIdsPlugin(),
  175. new ExtractTextPlugin({
  176. filename: '[name].[hash:8].css'
  177. }),
  178. new VersionPlugin(),
  179. new ManifestPlugin() // used by server side to resolve hashed assets
  180. ],
  181. devServer: {
  182. before: require('./server/bin/dev'),
  183. compress: true,
  184. hot: false,
  185. host: '0.0.0.0',
  186. proxy: {
  187. '/api/ws': {
  188. target: 'ws://localhost:8081',
  189. ws: true,
  190. secure: false
  191. }
  192. }
  193. }
  194. };
  195. module.exports = (env, argv) => {
  196. const mode = argv.mode || 'production';
  197. console.error(`mode: ${mode}`);
  198. web.mode = serviceWorker.mode = mode;
  199. if (mode === 'development') {
  200. // istanbul instruments the source for code coverage
  201. webJsOptions.plugins.push('istanbul');
  202. web.entry.tests = ['./test/frontend/index.js'];
  203. web.devtool = 'source-map';
  204. serviceWorker.devtool = 'source-map';
  205. }
  206. return [web, serviceWorker];
  207. };