GSA/code-gov-front-end

View on GitHub
config/webpack/webpack.shared.js

Summary

Maintainability
A
0 mins
Test Coverage
const path = require('path')
const { dirname, join, resolve } = require('path')
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const ImageminPlugin = require('imagemin-webpack-plugin').default
const DefinePlugin = require('webpack/lib/DefinePlugin')
const EnvironmentPlugin = require('webpack/lib/EnvironmentPlugin')
const marked = require('marked')

const markdownRenderer = new marked.Renderer()

const rootDir = dirname(dirname(__dirname))
const sass = require('sass')

const nodeModulesDir = join(rootDir, 'node_modules')
const siteConfigPath = process.env.CODE_GOV_CONFIG_JSON || join(rootDir, '/config/site/site.json')
const SITE_CONFIG = require(siteConfigPath)

require('dotenv-flow').config()

let PUBLIC_PATH = process.env.BASEURL || process.env.PUBLIC_PATH || '/'
let OUTPUT_PATH
const BRANCH = process.env.BRANCH || 'development'

// add slash to end of path for federalist branch builds
if (PUBLIC_PATH.slice(-1) !== '/') PUBLIC_PATH = `${PUBLIC_PATH}/`

if (process.env.OUTPUT_PATH) {
  OUTPUT_PATH = process.env.OUTPUT_PATH
} else if (process.env.OUTPUT_RELATIVE_PATH) {
  OUTPUT_PATH = join(rootDir, process.env.OUTPUT_RELATIVE_PATH)
} else {
  OUTPUT_PATH = join(rootDir, '/dist')
}

const patterns = [
  { from: 'styles', to: 'css' },
  { from: 'assets/data', to: 'assets/data' },
  { from: 'assets/img', to: 'assets/img' },
  {
    from: 'img/**/*',
    to: 'styles/uswds/',
    context: path.resolve(rootDir, 'node_modules', 'uswds', 'dist')
  },
  {
    from: './src/components/about/html',
    to: join(OUTPUT_PATH, '/src/components/about/html')
  },
  {
    from: './src/components/privacy-policy/html',
    to: join(OUTPUT_PATH, '/src/components/privacy-policy/html')
  },
  {
    from: './src/components/agency-compliance/html',
    to: join(OUTPUT_PATH, '/src/components/agency-compliance/html')
  },
  {
    from: './src/components/federal-agencies/html',
    to: join(OUTPUT_PATH, '/src/components/federal-agencies/html')
  },
  {
    from: 'fonts/**/*',
    to: 'uswds/',
    context: path.resolve(rootDir, 'node_modules', 'uswds', 'dist')
  },
  {
    from: 'fonts/*',
    to: 'uswds/',
    context: path.resolve(rootDir, 'assets')
  },
  {
    from: 'fonts/*',
    to: 'assets/',
    context: path.resolve(rootDir, 'assets')
  },
  {
    from: './404.html',
    to: join(OUTPUT_PATH, '404.html')
  },
  {
    from: 'node_modules/@webcomponents/custom-elements/custom-elements.min.js',
    to: 'polyfills/custom-elements.js'
  },
  {
    from: 'node_modules/custom-event-polyfill/polyfill.js',
    to: 'polyfills/custom-event.js'
  },
  {
    from: 'node_modules/whatwg-fetch/dist/fetch.umd.js',
    to: 'polyfills/fetch.js'
  },
  {
    from: 'node_modules/url-search-params-polyfill/index.js',
    to: 'polyfills/url-search-params.js'
  }
]

if (BRANCH.includes('production')) {
  // only include sitemap if building for production on code.gov
  patterns.push({
    from: 'node_modules/@code.gov/site-map-generator/sitemap.xml',
    to: join(OUTPUT_PATH, 'sitemap.xml')
  })
}

module.exports = {
  entry: {
    index: ['@babel/polyfill', './src/index.js']
  },
  resolve: {
    modules: ['node_modules', 'src', 'config', 'assets'],
    extensions: ['.js', '.json', '.md']
  },
  plugins: [
    new DefinePlugin({
      ENABLE_GOOGLE_ANALYTICS: BRANCH === 'production',
      ENABLE_FED_ANALYTICS: BRANCH === 'production' || BRANCH === 'staging',
      PUBLIC_PATH: JSON.stringify(PUBLIC_PATH),
      SITE_CONFIG: JSON.stringify(SITE_CONFIG)
    }),
    new EnvironmentPlugin(['CODE_GOV_API_BASE', 'CODE_GOV_API_KEY', 'CODE_GOV_TASKS_URL']),
    new CopyPlugin({ patterns }),
    new ImageminPlugin({ test: /\.(jpe?g|png|gif|svg)$/i }),
    new HtmlWebpackPlugin({
      hash: true,
      template: 'index.html',
      templateParameters: {
        PUBLIC_PATH
      },
      title: 'code.gov',
      minify: {
        removeScriptTypeAttributes: true
      }
    }),
    new FaviconsWebpackPlugin({
      logo: './assets/img/favicon.png',
      inject: true,
      prefix: join(PUBLIC_PATH, '/assets/img/favicons'),
      favicons: {
        developerURL: null, // prevent retrieving from the nearest package.json
        icons: {
          coast: false,
          yandex: false
        }
      }
    })
    // new CleanWebpackPlugin()
  ],
  devServer: {
    contentBase: path.join(rootDir, 'dist'),
    compress: true,
    writeToDisk: true,
    historyApiFallback: {
      index: 'index.html'
    },
    port: 8080
  },
  output: {
    chunkFilename: '[name].bundle.js',
    filename: '[name].bundle.js',
    path: OUTPUT_PATH,
    publicPath: PUBLIC_PATH
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            plugins: [
              '@babel/plugin-proposal-class-properties',
              '@babel/plugin-proposal-object-rest-spread',
              '@babel/plugin-transform-arrow-functions',
              '@babel/plugin-transform-classes',
              '@babel/plugin-syntax-dynamic-import',
              'babel-plugin-dynamic-import-node',
              'babel-plugin-transform-function-bind',
              '@babel/plugin-transform-regenerator'
            ],
            presets: ['@babel/preset-env', '@babel/preset-react']
          }
        }
      },
      {
        test: /\.(s*)css$/,
        use: [
          {
            loader: 'style-loader', // creates style nodes from JS strings
            options: {
              sourceMap: true
            }
          },
          {
            loader: 'css-loader', // translates CSS into CommonJS
            options: {
              sourceMap: true
            }
          },
          {
            loader: 'sass-loader', // compiles Sass to CSS
            options: {
              implementation: sass,
              sourceMap: true
            }
          }
        ]
      },
      {
        test: /\.md$/,
        use: [
          {
            loader: 'html-loader'
          },
          {
            loader: 'markdown-loader',
            options: {
              pedantic: true,
              renderer: markdownRenderer
            }
          }
        ]
      },
      {
        test: /\.(png)$/,
        loader: 'file-loader',
        options: {
          outputPath: 'images'
        }
      },
      {
        test: /\.(ttf|eot|woff|woff2|svg)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name].[ext]',
              outputPath: 'fonts/'
            }
          }
        ]
      }
    ]
  }
}