const path = require('path'); const webpack = require('webpack'); const PnpWebpackPlugin = require('pnp-webpack-plugin'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); const pckg = require('./package.json'); const absolutePath = location => path.resolve(__dirname, location); const locations = { // Shouldn't change root: absolutePath('.'), output: absolutePath('web'), rootHtml: absolutePath('web/index.html'), packageJson: absolutePath('package.json'), appMain: absolutePath(pckg.main), // TODO: Bacon: Only use this in expo/apps/ modules: absolutePath('../../node_modules'), }; const environment = process.env.NODE_ENV || 'development'; const __DEV__ = environment !== 'production'; const REACT_APP = /^REACT_APP_/i; const publicUrl = ''; function getClientEnvironment(publicUrl) { let processEnv = Object.keys(process.env) .filter(key => REACT_APP.test(key)) .reduce( (env, key) => { env[key] = JSON.stringify(process.env[key]); return env; }, { // Useful for determining whether we’re running in production mode. // Most importantly, it switches React into the correct mode. NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'), // Useful for resolving the correct path to static assets in `public`. // For example, . // This should only be used as an escape hatch. Normally you would put // images into the `src` and `import` them in code to get their paths. PUBLIC_URL: JSON.stringify(publicUrl), } ); return { 'process.env': processEnv, __DEV__, }; } const env = getClientEnvironment(publicUrl); const includeModule = module => { return path.resolve(locations.modules, module); }; const babelLoaderConfiguration = { test: /\.jsx?$/, include: [ // TODO: Bacon: This makes compilation take a while locations.root, locations.modules, ], use: { loader: 'babel-loader', options: { babelrc: false, }, }, }; // This is needed for webpack to import static images in JavaScript files. const imageLoaderConfiguration = { test: /\.(gif|jpe?g|png|svg)$/, use: { loader: 'url-loader', options: { limit: 10000, name: '[name].[ext]', }, }, }; // This is needed for loading css const cssLoaderConfiguration = { test: /\.css$/, use: ['style-loader', 'css-loader'], }; const ttfLoaderConfiguration = { test: /\.ttf$/, use: [ { loader: 'file-loader', options: { name: './fonts/[hash].[ext]', }, }, ], include: [ locations.root, includeModule('react-native-vector-icons'), includeModule('@expo/vector-icons'), ], }; const htmlLoaderConfiguration = { test: /\.html$/, use: ['html-loader'], include: [absolutePath('./assets')], }; const videoLoaderConfiguration = { test: /\.(mov|mp4)$/, use: [ { loader: 'file-loader', options: { name: '[path][name].[ext]', }, }, ], }; function getWebModule(moduleName, initialRoot, logTag) { return function(res) { if (res.context.indexOf('node_modules/react-native/') === -1) return; res.request = includeModule(initialRoot + moduleName); }; } function useWebModules(modules, initialRoot = 'react-native-web/dist/exports/', logTag) { return modules.map(module => { let moduleName = module; let proxyName = module; if (Array.isArray(module)) { moduleName = module[0]; proxyName = module[1]; } return new webpack.NormalModuleReplacementPlugin( new RegExp(moduleName), getWebModule(proxyName, initialRoot, logTag) ); }); } const publicPath = '/'; module.exports = { mode: 'development', devtool: 'cheap-module-source-map', entry: [require.resolve('react-dev-utils/webpackHotDevClient'), locations.appMain], // configures where the build ends up output: { path: locations.output, pathinfo: true, filename: 'bundle.js', // There are also additional JS chunk files if you use code splitting. chunkFilename: '[name].chunk.js', // This is the URL that app is served from. We use "/" in development. publicPath, // Point sourcemap entries to original disk location (format as URL on Windows) devtoolModuleFilenameTemplate: info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'), }, optimization: { runtimeChunk: true, }, devServer: { progress: true, historyApiFallback: true, compress: true, disableHostCheck: true, contentBase: locations.output, inline: true, }, module: { rules: [ { parser: { requireEnsure: false } }, htmlLoaderConfiguration, babelLoaderConfiguration, cssLoaderConfiguration, imageLoaderConfiguration, ttfLoaderConfiguration, videoLoaderConfiguration, ], }, plugins: [ // Generates an `index.html` file with the