Подскажите пожалуйста, есть вот файл 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;
Устанавливаете 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'
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Я делаю свое собственное расширение Chrome на JS, поэтому, мне нaдo получать куки с нужного сайтаНо я не знаю, какой метод мне использовать
Как сделать такую подсветку как например у нас на stackoverflow?
Для работы с объектами в массиве решил попробовать for each (for (const item in array) {}), но столкнулся с проблемой - почему последний item не число, а слово...