BigW Consortium Gitlab

webpack.config.js 8.88 KB
Newer Older
1 2
'use strict';

3
var fs = require('fs');
4 5 6
var path = require('path');
var webpack = require('webpack');
var StatsPlugin = require('stats-webpack-plugin');
7
var CompressionPlugin = require('compression-webpack-plugin');
8
var NameAllModulesPlugin = require('name-all-modules-plugin');
9
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
10
var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
11

12
var ROOT_PATH = path.resolve(__dirname, '..');
13
var IS_PRODUCTION = process.env.NODE_ENV === 'production';
14
var IS_DEV_SERVER = process.argv.join(' ').indexOf('webpack-dev-server') !== -1;
15
var DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost';
16
var DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808;
17
var DEV_SERVER_LIVERELOAD = process.env.DEV_SERVER_LIVERELOAD !== 'false';
18
var WEBPACK_REPORT = process.env.WEBPACK_REPORT;
19
var NO_COMPRESSION = process.env.NO_COMPRESSION;
20 21

var config = {
22 23 24 25
  // because sqljs requires fs.
  node: {
    fs: "empty"
  },
26
  context: path.join(ROOT_PATH, 'app/assets/javascripts'),
27
  entry: {
28
    balsamiq_viewer:      './blob/balsamiq_viewer.js',
29 30
    blob:                 './blob_edit/blob_bundle.js',
    boards:               './boards/boards_bundle.js',
31
    common:               './commons/index.js',
32
    common_vue:           ['vue', './vue_shared/common_vue.js'],
33
    common_d3:            ['d3'],
34
    cycle_analytics:      './cycle_analytics/cycle_analytics_bundle.js',
35
    commit_pipelines:     './commit/pipelines/pipelines_bundle.js',
36
    deploy_keys:          './deploy_keys/index.js',
37 38
    diff_notes:           './diff_notes/diff_notes_bundle.js',
    environments:         './environments/environments_bundle.js',
Filipa Lacerda committed
39
    environments_folder:  './environments/folder/environments_folder_bundle.js',
40
    filtered_search:      './filtered_search/filtered_search_bundle.js',
41
    graphs:               './graphs/graphs_bundle.js',
42
    group:                './group.js',
43
    groups:               './groups/index.js',
44
    groups_list:          './groups_list.js',
45
    issue_show:           './issue_show/index.js',
kushalpandya committed
46
    integrations:         './integrations',
47
    job_details:          './jobs/job_details_bundle.js',
Phil Hughes committed
48
    locale:               './locale/index.js',
49
    main:                 './main.js',
50
    merge_conflicts:      './merge_conflicts/merge_conflicts_bundle.js',
51
    monitoring:           './monitoring/monitoring_bundle.js',
52
    network:              './network/network_bundle.js',
53
    notebook_viewer:      './blob/notebook_viewer.js',
54
    pdf_viewer:           './blob/pdf_viewer.js',
55
    pipelines:            './pipelines/pipelines_bundle.js',
56
    pipelines_details:     './pipelines/pipeline_details_bundle.js',
57
    profile:              './profile/profile_bundle.js',
58
    prometheus_metrics:   './prometheus_metrics',
59
    protected_branches:   './protected_branches/protected_branches_bundle.js',
60
    protected_tags:       './protected_tags',
61
    sidebar:              './sidebar/sidebar_bundle.js',
62 63
    schedule_form:        './pipeline_schedules/pipeline_schedule_form_bundle.js',
    schedules_index:      './pipeline_schedules/pipeline_schedules_index_bundle.js',
64
    snippet:              './snippet/snippet_bundle.js',
65
    sketch_viewer:        './blob/sketch_viewer.js',
Phil Hughes committed
66
    stl_viewer:           './blob/stl_viewer.js',
67
    terminal:             './terminal/terminal_bundle.js',
68
    u2f:                  ['vendor/u2f'],
69
    users:                './users/users_bundle.js',
70
    raven:                './raven/index.js',
71
    vue_merge_request_widget: './vue_merge_request_widget/index.js',
72
    test:                 './test.js',
73
    peek:                 './peek.js',
74
    webpack_runtime:      './webpack.js',
75 76 77 78 79
  },

  output: {
    path: path.join(ROOT_PATH, 'public/assets/webpack'),
    publicPath: '/assets/webpack/',
80 81
    filename: IS_PRODUCTION ? '[name].[chunkhash].bundle.js' : '[name].bundle.js',
    chunkFilename: IS_PRODUCTION ? '[name].[chunkhash].chunk.js' : '[name].chunk.js',
82 83
  },

84
  module: {
85
    rules: [
86
      {
87
        test: /\.js$/,
88
        exclude: /(node_modules|vendor\/assets)/,
89
        loader: 'babel-loader',
90
      },
91 92
      {
        test: /\.vue$/,
93
        loader: 'vue-loader',
94
      },
95 96
      {
        test: /\.svg$/,
97 98
        loader: 'raw-loader',
      },
Sam Rose committed
99
      {
100
        test: /\.(gif|png)$/,
Sam Rose committed
101
        loader: 'url-loader',
102
        options: { limit: 2048 },
Sam Rose committed
103
      },
104
      {
105
        test: /\.(worker\.js|pdf|bmpr)$/,
106 107 108
        exclude: /node_modules/,
        loader: 'file-loader',
      },
109
      {
110
        test: /locale\/\w+\/(.*)\.js$/,
111 112
        loader: 'exports-loader?locales',
      },
113 114 115
    ]
  },

116 117 118 119 120 121 122 123 124
  plugins: [
    // manifest filename must match config.webpack.manifest_filename
    // webpack-rails only needs assetsByChunkName to function properly
    new StatsPlugin('manifest.json', {
      chunkModules: false,
      source: false,
      chunks: false,
      modules: false,
      assets: true
Phil Hughes committed
125
    }),
126 127

    // prevent pikaday from including moment.js
128
    new webpack.IgnorePlugin(/moment/, /pikaday/),
129

130 131 132 133 134 135
    // fix legacy jQuery plugins which depend on globals
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),

136
    // assign deterministic module ids
137
    new webpack.NamedModulesPlugin(),
138
    new NameAllModulesPlugin(),
139

140 141 142 143 144 145 146 147 148 149 150
    // assign deterministic chunk ids
    new webpack.NamedChunksPlugin((chunk) => {
      if (chunk.name) {
        return chunk.name;
      }
      return chunk.modules.map((m) => {
        var chunkPath = m.request.split('!').pop();
        return path.relative(m.context, chunkPath);
      }).join('_');
    }),

151 152 153 154 155 156 157
    // create cacheable common library bundle for all vue chunks
    new webpack.optimize.CommonsChunkPlugin({
      name: 'common_vue',
      chunks: [
        'boards',
        'commit_pipelines',
        'cycle_analytics',
Phil Hughes committed
158
        'deploy_keys',
159 160 161
        'diff_notes',
        'environments',
        'environments_folder',
162
        'filtered_search',
Alfredo Sumaran committed
163
        'groups',
164
        'issue_show',
165
        'job_details',
166
        'merge_conflicts',
167
        'monitoring',
168
        'notebook_viewer',
169
        'pdf_viewer',
170
        'pipelines',
171
        'pipelines_details',
172 173 174
        'schedule_form',
        'schedules_index',
        'sidebar',
175
        'vue_merge_request_widget',
176
      ],
177 178 179
      minChunks: function(module, count) {
        return module.resource && (/vue_shared/).test(module.resource);
      },
180 181
    }),

182 183 184
    // create cacheable common library bundle for all d3 chunks
    new webpack.optimize.CommonsChunkPlugin({
      name: 'common_d3',
185 186 187 188 189
      chunks: [
        'graphs',
        'users',
        'monitoring',
      ],
190 191
    }),

192
    // create cacheable common library bundles
193
    new webpack.optimize.CommonsChunkPlugin({
194
      names: ['main', 'locale', 'common', 'webpack_runtime'],
195
    }),
196 197 198
  ],

  resolve: {
199
    extensions: ['.js'],
200
    alias: {
201
      '~':              path.join(ROOT_PATH, 'app/assets/javascripts'),
202
      'emojis':         path.join(ROOT_PATH, 'fixtures/emojis'),
203
      'empty_states':   path.join(ROOT_PATH, 'app/views/shared/empty_states'),
204
      'icons':          path.join(ROOT_PATH, 'app/views/shared/icons'),
205
      'images':         path.join(ROOT_PATH, 'app/assets/images'),
206
      'vendor':         path.join(ROOT_PATH, 'vendor/assets/javascripts'),
207
      'vue$':           'vue/dist/vue.esm.js',
208
    }
209
  }
210 211
}

212
if (IS_PRODUCTION) {
213
  config.devtool = 'source-map';
214
  config.plugins.push(
215
    new webpack.NoEmitOnErrorsPlugin(),
216 217 218 219
    new webpack.LoaderOptionsPlugin({
      minimize: true,
      debug: false
    }),
220
    new webpack.optimize.UglifyJsPlugin({
221
      sourceMap: true
222 223 224
    }),
    new webpack.DefinePlugin({
      'process.env': { NODE_ENV: JSON.stringify('production') }
Mike Greiling committed
225
    })
226
  );
227

228
  // zopfli requires a lot of compute time and is disabled in CI
229
  if (!NO_COMPRESSION) {
230 231 232 233 234 235
    // gracefully fall back to gzip if `node-zopfli` is unavailable (e.g. in CentOS 6)
    try {
      config.plugins.push(new CompressionPlugin({ algorithm: 'zopfli' }));
    } catch(err) {
      config.plugins.push(new CompressionPlugin({ algorithm: 'gzip' }));
    }
236
  }
237 238 239
}

if (IS_DEV_SERVER) {
240
  config.devtool = 'cheap-module-eval-source-map';
241
  config.devServer = {
242
    host: DEV_SERVER_HOST,
243
    port: DEV_SERVER_PORT,
244 245
    headers: { 'Access-Control-Allow-Origin': '*' },
    stats: 'errors-only',
246
    hot: DEV_SERVER_LIVERELOAD,
247
    inline: DEV_SERVER_LIVERELOAD
248
  };
249 250 251 252
  config.plugins.push(
    // watch node_modules for changes if we encounter a missing module compile error
    new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules'))
  );
253 254 255
  if (DEV_SERVER_LIVERELOAD) {
    config.plugins.push(new webpack.HotModuleReplacementPlugin());
  }
256 257
}

258 259 260 261 262 263 264 265 266 267 268 269
if (WEBPACK_REPORT) {
  config.plugins.push(
    new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      generateStatsFile: true,
      openAnalyzer: false,
      reportFilename: path.join(ROOT_PATH, 'webpack-report/index.html'),
      statsFilename: path.join(ROOT_PATH, 'webpack-report/stats.json'),
    })
  );
}

270
module.exports = config;