Skip to content
Snippets Groups Projects
webpack.config.js 8.02 KiB
Newer Older
// Variables in .env and .env.defaults will be added to process.env
const dotenv = require("dotenv");
dotenv.config({ path: ".env" });
dotenv.config({ path: ".env.defaults" });

const fs = require("fs");
const path = require("path");
const selfsigned = require("selfsigned");
const webpack = require("webpack");
const cors = require("cors");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
Greg Fodor's avatar
Greg Fodor committed
const CopyWebpackPlugin = require("copy-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");

function createHTTPSConfig() {
  // Generate certs for the local webpack-dev-server.
  if (fs.existsSync(path.join(__dirname, "certs"))) {
    const key = fs.readFileSync(path.join(__dirname, "certs", "key.pem"));
    const cert = fs.readFileSync(path.join(__dirname, "certs", "cert.pem"));

    return { key, cert };
  } else {
    const pems = selfsigned.generate(
      [
        {
          name: "commonName",
          value: "localhost"
        }
      ],
      {
        days: 365,
        algorithm: "sha256",
        extensions: [
          {
            name: "subjectAltName",
            altNames: [
              {
                type: 2,
                value: "localhost"
Greg Fodor's avatar
Greg Fodor committed
                value: "hubs.local"
              }
            ]
          }
        ]
      }
    );

    fs.mkdirSync(path.join(__dirname, "certs"));
    fs.writeFileSync(path.join(__dirname, "certs", "cert.pem"), pems.cert);
    fs.writeFileSync(path.join(__dirname, "certs", "key.pem"), pems.private);

    return {
      key: pems.private,
module.exports = (env, argv) => ({
    index: path.join(__dirname, "src", "index.js"),
    hub: path.join(__dirname, "src", "hub.js"),
Greg Fodor's avatar
Greg Fodor committed
    scene: path.join(__dirname, "src", "scene.js"),
Greg Fodor's avatar
Greg Fodor committed
    link: path.join(__dirname, "src", "link.js"),
    spoke: path.join(__dirname, "src", "spoke.js"),
Greg Fodor's avatar
Greg Fodor committed
    "avatar-selector": path.join(__dirname, "src", "avatar-selector.js")
    filename: "assets/js/[name]-[chunkhash].js",
    publicPath: process.env.BASE_ASSETS_PATH || ""
  devtool: argv.mode === "production" ? "source-map" : "inline-source-map",
  devServer: {
    https: createHTTPSConfig(),
Greg Fodor's avatar
Greg Fodor committed
    host: "0.0.0.0",
Brian Peiris's avatar
Brian Peiris committed
    public: "hubs.local:8080",
    useLocalIp: true,
    allowedHosts: ["hubs.local"],
    before: function(app) {
      // be flexible with people accessing via a local reticulum on another port
      app.use(cors({ origin: /hubs\.local(:\d*)?$/ }));
      // networked-aframe makes HEAD requests to the server for time syncing. Respond with an empty body.
      app.head("*", function(req, res, next) {
        if (req.method === "HEAD") {
Greg Fodor's avatar
Greg Fodor committed
          res.append("Date", new Date().toGMTString());
          res.send("");
        } else {
          next();
        }
      });
    }
  },
  performance: {
    // Ignore media and sourcemaps when warning about file size.
    assetFilter(assetFilename) {
Greg Fodor's avatar
Greg Fodor committed
      return !/\.(map|png|jpg|gif|glb|webm)$/.test(assetFilename);
    }
  },
  module: {
    rules: [
      {
        test: /\.html$/,
        loader: "html-loader",
        options: {
          // <a-asset-item>'s src property is overwritten with the correct transformed asset url.
          attrs: ["img:src", "a-asset-item:src", "audio:src", "source:src"]
      {
        test: /\.worker\.js$/,
        loader: "worker-loader",
        options: {
          name: "assets/js/[name]-[hash].js",
netpro2k's avatar
netpro2k committed
          publicPath: "/",
          inline: true
      {
        test: /\.js$/,
        include: [path.resolve(__dirname, "src")],
        // Exclude JS assets in node_modules because they are already transformed and often big.
        exclude: [path.resolve(__dirname, "node_modules")],
        loader: "babel-loader"
        test: /\.(scss|css)$/,
Greg Fodor's avatar
Greg Fodor committed
        loader: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: [
            {
              loader: "css-loader",
              options: {
Greg Fodor's avatar
Greg Fodor committed
                name: "[path][name]-[hash].[ext]",
                localIdentName: "[name]__[local]__[hash:base64:5]",
                camelCase: true
Greg Fodor's avatar
Greg Fodor committed
              }
            },
            "sass-loader"
          ]
        })
      },
        test: /\.(png|jpg|gif|glb|ogg|mp3|mp4|wav|woff2|svg|webm)$/,
        use: {
          loader: "file-loader",
          options: {
            // move required assets to output dir and add a hash for cache busting
            name: "[path][name]-[hash].[ext]",
            // Make asset paths relative to /src
            context: path.join(__dirname, "src")
          }
        }
      },
      {
        test: /\.(glsl)$/,
        use: { loader: "raw-loader" }
  optimization: {
    // necessary due to https://github.com/visionmedia/debug/issues/547
    minimizer: [new UglifyJsPlugin({ sourceMap: true, uglifyOptions: { compress: { collapse_vars: false } } })],
    splitChunks: {
      cacheGroups: {
        engine: {
          test: /([\\/]src[\\/]workers|[\\/]node_modules[\\/](aframe|cannon|three\.js))/,
          priority: 100,
          name: "engine",
          chunks: "all"
        },
        vendors: {
          test: /([\\/]node_modules[\\/]|[\\/]vendor[\\/])/,
          priority: 50,
          name: "vendor",
          chunks: "all"
        }
      }
    }
  plugins: [
    // Each output page needs a HTMLWebpackPlugin entry
    new HTMLWebpackPlugin({
      filename: "index.html",
      template: path.join(__dirname, "src", "index.html"),
      chunks: ["vendor", "index"]
    }),
    new HTMLWebpackPlugin({
      filename: "hub.html",
      template: path.join(__dirname, "src", "hub.html"),
      chunks: ["vendor", "engine", "hub"],
      inject: "head",
      meta: [
        {
          "http-equiv": "origin-trial",
          "data-feature": "WebVR (For Chrome M62+)",
          "data-expires": process.env.ORIGIN_TRIAL_EXPIRES,
Marshall Quander's avatar
Marshall Quander committed
          content: process.env.ORIGIN_TRIAL_TOKEN
Greg Fodor's avatar
Greg Fodor committed
    new HTMLWebpackPlugin({
      filename: "scene.html",
      template: path.join(__dirname, "src", "scene.html"),
      chunks: ["vendor", "engine", "scene"],
      inject: "head",
      meta: [
        {
          "http-equiv": "origin-trial",
          "data-feature": "WebVR (For Chrome M62+)",
          "data-expires": process.env.ORIGIN_TRIAL_EXPIRES,
          content: process.env.ORIGIN_TRIAL_TOKEN
        }
      ]
    }),
Greg Fodor's avatar
Greg Fodor committed
    new HTMLWebpackPlugin({
      filename: "link.html",
      template: path.join(__dirname, "src", "link.html"),
      chunks: ["vendor", "link"]
Greg Fodor's avatar
Greg Fodor committed
    }),
    new HTMLWebpackPlugin({
      filename: "spoke.html",
      template: path.join(__dirname, "src", "spoke.html"),
      chunks: ["vendor", "spoke"]
    }),
    new HTMLWebpackPlugin({
      filename: "avatar-selector.html",
      template: path.join(__dirname, "src", "avatar-selector.html"),
      chunks: ["vendor", "engine", "avatar-selector"],
      inject: "head"
    }),
Greg Fodor's avatar
Greg Fodor committed
    new CopyWebpackPlugin([
      {
        from: "src/assets/images/favicon.ico",
        to: "favicon.ico"
      }
    ]),
    new CopyWebpackPlugin([
      {
        from: "src/assets/images/hub-preview.png",
        to: "hub-preview.png"
      }
    ]),
Greg Fodor's avatar
Greg Fodor committed
    new CopyWebpackPlugin([
      {
        from: "src/hub.service.js",
        to: "hub.service.js"
      }
    ]),
    // Extract required css and add a content hash.
    new ExtractTextPlugin({
Marshall Quander's avatar
Marshall Quander committed
      filename: "assets/stylesheets/[name]-[md5:contenthash:hex:20].css",
      disable: argv.mode !== "production"
    }),
    // Define process.env variables in the browser context.
    new webpack.DefinePlugin({
      "process.env": JSON.stringify({
        NODE_ENV: argv.mode,
Greg Fodor's avatar
Greg Fodor committed
        JANUS_SERVER: process.env.JANUS_SERVER,
        RETICULUM_SERVER: process.env.RETICULUM_SERVER,
        FARSPARK_SERVER: process.env.FARSPARK_SERVER,
        ASSET_BUNDLE_SERVER: process.env.ASSET_BUNDLE_SERVER,
        EXTRA_ENVIRONMENTS: process.env.EXTRA_ENVIRONMENTS,
        BUILD_VERSION: process.env.BUILD_VERSION