Разделить API config на версию dev и prod webpack

304
23 декабря 2021, 00:10

Подскажите пожалуйста, есть вот файл config.js в нем экспортируемая переменная с ссылкой на API, но есть API для dev версии, а есть отдельное API для prod версии, я так понимаю нужно сделать 2 отдельных файла, но как сделать в webpack так чтоб при dev он юзал один файл, а prod другой?

Ниже добавил файлы конфигурации webpack, проект на react.js (если это имеет какое-то значение :) )

rules.js

const rules = [ 
  { 
    test: /\.jsx?$/, 
    exclude: /node_modules/, 
    use: ['babel-loader'], 
  }, 
  { 
    test: /\.eot(\?v=\d+.\d+.\d+)?$/, 
    use: [ 
      { 
        loader: 'url-loader', 
        options: { 
          name: '[name].[ext]', 
        }, 
      }, 
    ], 
  }, 
  { 
    test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, 
    use: [ 
      { 
        loader: 'url-loader', 
        options: { 
          limit: 10000, 
          mimetype: 'application/font-woff', 
          name: '[name].[ext]', 
        }, 
      }, 
    ], 
  }, 
  { 
    test: /\.[ot]tf(\?v=\d+.\d+.\d+)?$/, 
    use: [ 
      { 
        loader: 'url-loader', 
        options: { 
          limit: 10000, 
          mimetype: 'application/octet-stream', 
          name: '[name].[ext]', 
        }, 
      }, 
    ], 
  }, 
  { 
    test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 
    use: [ 
      { 
        loader: 'url-loader', 
        options: { 
          limit: 10000, 
          mimetype: 'image/svg+xml', 
          name: '[name].[ext]', 
        }, 
      }, 
    ], 
  }, 
  { 
    test: /\.(jpe?g|png|gif|ico)$/i, 
    use: [ 
      { 
        loader: 'file-loader', 
        options: { 
          name: '[name].[ext]', 
        }, 
      }, 
    ], 
  }, 
]; 
 
export default rules;

webpack.config.common.babel.js

import path from 'path'; 
import HtmlWebpackPlugin from 'html-webpack-plugin'; 
import Dotenv from 'dotenv-webpack'; 
import rules from './utils/rules'; 
 
const config = (env) => { 
  const PUBLIC_PATH = env.production ? '/' : '/'; 
 
  return { 
    entry: { 
      index: './src/index.js' 
    }, 
    output: { 
      publicPath: PUBLIC_PATH, 
      path: path.resolve(process.cwd(), 'dist'), 
      filename: env.production ? '[name].js' : '[name].bundle.js' 
    }, 
    resolve: { 
      alias: { 
        'react-dom': '@hot-loader/react-dom', 
        app: path.resolve(process.cwd(), 'src/app/'), 
        store: path.resolve(process.cwd(), 'src/store/'), 
        ui: path.resolve(process.cwd(), 'src/ui/') 
      }, 
      extensions: ['*', '.js', '.jsx', '.json', 'scss'] 
    }, 
    module: { 
      rules 
    }, 
    node: { 
      dgram: 'empty', 
      fs: 'empty', 
      net: 'empty', 
      tls: 'empty', 
      child_process: 'empty' 
    }, 
    plugins: [ 
      new Dotenv({ 
        systemvars: true 
      }), 
      new HtmlWebpackPlugin({ 
        template: 'public/index.html', 
        favicon: 'public/favicon.ico', 
        inject: true, 
        minify: { 
          removeComments: true, 
          collapseWhitespace: true, 
          removeRedundantAttributes: true, 
          useShortDoctype: true, 
          removeEmptyAttributes: true, 
          removeStyleLinkTypeAttributes: true, 
          keepClosingSlash: true, 
          minifyJS: true, 
          minifyCSS: true, 
          minifyURLs: true 
        } 
      }) 
    ] 
  }; 
}; 
 
export default config;

webpack.config.dev.babel.js

import webpack from 'webpack'; 
import path from 'path'; 
import merge from 'webpack-merge'; 
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 
import common from './webpack.config.common.babel'; 
 
const config = env => merge(common(env), { 
  devtool: 'cheap-module-eval-source-map', 
  target: 'web', 
  mode: 'development', 
  optimization: { 
    minimize: false 
  }, 
  performance: { 
    hints: false 
  }, 
  devServer: { 
    historyApiFallback: true, 
    contentBase: '../dist', 
    port: 3009, 
    hot: true, 
    clientLogLevel: 'none' 
  }, 
  module: { 
    rules: [ 
      { 
        test: /\.js$/, 
        exclude: /node_modules/, 
        use: ['babel-loader', 'eslint-loader'] 
      }, 
      { 
        test: /(\.css|\.scss|\.sass)$/, 
        use: [ 
          { 
            loader: 'style-loader', 
            options: { singleton: true } 
          }, 
          { 
            loader: 'css-loader' 
          }, 
          { 
            loader: 'postcss-loader', 
            options: { 
              /* eslint-disable global-require */ 
              plugins: () => [require('autoprefixer')], 
              sourceMap: true 
            } 
          }, 
          { 
            loader: 'sass-loader', 
            options: { 
              includePaths: [path.resolve(__dirname, 'src', 'scss')] 
            } 
          } 
        ] 
      } 
    ] 
  }, 
  plugins: [ 
    new webpack.NamedModulesPlugin(), 
    // new BundleAnalyzerPlugin(), 
    new webpack.NoEmitOnErrorsPlugin(), 
    new webpack.HotModuleReplacementPlugin() 
  ] 
}); 
 
export default config;

webpack.config.common.babel.js

import path from 'path'; 
import webpack from 'webpack'; 
import merge from 'webpack-merge'; 
import MiniCssExtractPlugin from 'mini-css-extract-plugin'; 
import common from './webpack.config.common.babel'; 
 
const config = env => merge(common(env), { 
  devtool: 'source-map', 
  target: 'web', 
  mode: 'production', 
  optimization: { 
    minimize: true, 
    nodeEnv: 'production', 
    sideEffects: true, 
    concatenateModules: true, 
    runtimeChunk: 'single', 
    splitChunks: { 
      cacheGroups: { 
        vendor: { 
          test: /[\\/]node_modules[\\/]/, 
          name: 'vendors', 
          chunks: 'all', 
        }, 
      }, 
    }, 
  }, 
  module: { 
    rules: [ 
      { 
        test: /(\.css|\.scss|\.sass)$/, 
        use: [ 
          MiniCssExtractPlugin.loader, 
          { 
            loader: 'css-loader', 
            options: { 
              sourceMap: true, 
            }, 
          }, 
          { 
            loader: 'postcss-loader', 
            options: { 
              /* eslint-disable global-require */ 
              plugins: () => [require('cssnano'), require('autoprefixer')], 
              sourceMap: true, 
            }, 
          }, 
          { 
            loader: 'sass-loader', 
            options: { 
              includePaths: [path.resolve(__dirname, 'src', 'scss')], 
              sourceMap: true, 
            }, 
          }, 
        ], 
      }, 
    ], 
  }, 
  plugins: [ 
    new webpack.HashedModuleIdsPlugin(), 
    new MiniCssExtractPlugin({ 
      filename: '[name].[chunkhash].css', 
    }) 
  ], 
}); 
 
export default config;

Answer 1

Устанавливаете webpack-merge.

Делайте общий конфиг для дев и прод - client.webpack.base.js

Когда нужен дев, мержите общий к деву (с нужными вам файлами в том числе) и запускаете:

// webpack.dev.js
const webpack = require('webpack')
const merge = require('webpack-merge')
const base = require('./client.webpack.base.js')
module.exports = merge(base, {
  mode: 'development',
  watch: true,
  plugins: [
    new webpack.DefinePlugin({
      isProd: false
    })
  ]
})

Когда нужен прод, мержите прод к общему и запускаете уже этот файл:

// webpack.prod.js
const merge = require('webpack-merge')
const base = require('./client.webpack.base.js')
const webpack = require('webpack')
module.exports = merge(base, {
  mode: 'production',
  watch: false,
  plugins: [
    new webpack.DefinePlugin({
      isProd: true
    })
  ]
})

Переменная isProd работает внутри любого файла, имея соответствующее значение. Её и используете для определения чего хотите:

// В любом реакт компоненте
const api = isProd ? 'api/dev' : 'api/prod'
READ ALSO
Какой метод использовать для получения cookies?

Какой метод использовать для получения cookies?

Я делаю свое собственное расширение Chrome на JS, поэтому, мне нaдo получать куки с нужного сайтаНо я не знаю, какой метод мне использовать

193
Как реализовать подсветку в <code> html js?

Как реализовать подсветку в <code> html js?

Как сделать такую подсветку как например у нас на stackoverflow?

158
Почему в js последний индекс for each - remove? [дубликат]

Почему в js последний индекс for each - remove? [дубликат]

Для работы с объектами в массиве решил попробовать for each (for (const item in array) {}), но столкнулся с проблемой - почему последний item не число, а слово...

122