I can't get a simple video to load/play, so I decided to try looking at the webpack file and it seems fine. The code is below.
const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getClientEnvironment = require('./env');
const paths = require('./paths');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const host = process.env.HOST || '0.0.0.0';
const port = parseInt(process.env.PORT, 10) || 3000;
const publicPath = `${protocol}://${host}:${port}/`;
const publicUrl = '';
const env = getClientEnvironment(publicUrl);
module.exports = {
devtool: 'cheap-module-source-map',
entry: [
require.resolve('./polyfills'),
require.resolve('webpack-dev-server/client') + `?${publicPath}`,
require.resolve('webpack/hot/dev-server'),
paths.appIndexJs,
],
output: {
pathinfo: true,
filename: 'static/js/bundle.js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
},
resolve: {
modules: ['node_modules', paths.appNodeModules].concat(
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
alias: {
'react-native': 'react-native-web',
},
plugins: [
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.(js|jsx|mjs)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter,
eslintPath: require.resolve('eslint'),
},
loader: require.resolve('eslint-loader'),
},
],
include: paths.appSrc,
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
cacheDirectory: true,
},
},
{
test: /\.css$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
],
},
{
test: /\.(html)$/,
loader: require.resolve('html-loader'),
},
{
test: /\.mp4$/,
use: [
{
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]'
}
}
]
},
{
exclude: [/\.js$/, /\.html$/, /\.json$/],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
],
},
],
},
plugins: [
new InterpolateHtmlPlugin(env.raw),
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
new webpack.NamedModulesPlugin(),
new webpack.DefinePlugin(env.stringified),
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
performance: {
hints: false,
},
target: 'node-webkit',
};
This is my App.js below. I took out everything that doesn't matter. It's a simple call to an mp4 file.
import React, { Component } from 'react';
import { curious } from '#curi/react';
import AttractLoop from '../../assets/videos/video.mp4';
class App extends Component {
render() {
return (
<div className="app-container">
<div className="attract-loop">
<video width="1080" height="1920">
<source src={ AttractLoop } type="video/mp4" />
</video>
</div>
</div>
);
}
}
export default curious(App);
And here's a screenshot of my code inspector:
Update 1
I'm even trying to use this code from this SO question:
<video width="1080" height="1920" autoPlay loop src={ AttractLoop } type="video/mp4" />
Update 2
I downloaded the example Big Buck Bunny video to rule out that my video was encoded incorrectly. Getting the same result, a blank page.
I wanted to place the answer to the real issue, although #Jonny had some good webpack changes that should help others.
My Create React App is mixed with Nw.js, which is a platform that allows users to create exe files from their projects. I found out from https://github.com/naviapps/create-nw-react-app/issues/6 that NW.js does not allow mp4s by default so I needed to either configure my project settings to accept them or change the format of my video to ogv (or others).
The problem here is that your webpack.config.js is set up to output your media to a static directory. With ExpressJS, the static directory that you define should not be used in the public path. That path maps to the root of your public path. To fix this problem, you need to tweak your webpack.config.js to still output to this static directory, but not write it to the filename when its loaded with file-loader. Try something like this:
module.exports = {
devtool: 'cheap-module-source-map',
entry: [
require.resolve('./polyfills'),
require.resolve('webpack-dev-server/client') + `?${publicPath}`,
require.resolve('webpack/hot/dev-server'),
paths.appIndexJs,
],
output: {
pathinfo: true,
filename: 'js/bundle.js',
chunkFilename: 'js/[name].chunk.js',
// double check that this has it's backslashes in the right place
path: path.resolve(__dirname, publicPath + '/static'),
publicPath: publicPath',
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
},
resolve: {
modules: ['node_modules', paths.appNodeModules].concat(
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
alias: {
'react-native': 'react-native-web',
},
plugins: [
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.(js|jsx|mjs)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter,
eslintPath: require.resolve('eslint'),
},
loader: require.resolve('eslint-loader'),
},
],
include: paths.appSrc,
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
//name: 'static/media/[name].[hash:8].[ext]',
name: 'media/[name].[hash:8].[ext]',
},
},
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
cacheDirectory: true,
},
},
{
test: /\.css$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
],
},
{
test: /\.(html)$/,
loader: require.resolve('html-loader'),
},
{
test: /\.mp4$/,
use: [
{
loader: require.resolve('file-loader'),
options: {
//name: 'static/media/[name].[hash:8].[ext]'
name: 'media/[name].[hash:8].[ext]'
}
}
]
},
{
exclude: [/\.js$/, /\.html$/, /\.json$/],
loader: require.resolve('file-loader'),
options: {
//name: 'static/media/[name].[hash:8].[ext]',
name: 'media/[name].[hash:8].[ext]',
},
},
],
},
],
},
plugins: [
new InterpolateHtmlPlugin(env.raw),
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
new webpack.NamedModulesPlugin(),
new webpack.DefinePlugin(env.stringified),
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
performance: {
hints: false,
},
target: 'node-webkit',
};
Related
After I've added webpack in my react app, once the webpack started, it shows the white screen, and the whole bundle gets downloaded at one time. Even though I've done code splitting in react.
my webpack config:
/* eslint-disable no-un`enter code here`def */
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const HtmlWebpackInjectPreload = require("#principalstudio/html-webpack-inject-preload");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: path.resolve(__dirname, './index.js'),
devtool: "inline-source-map",
output: {
path: path.resolve(__dirname, "build"),
filename: "bundle.js",
publicPath: '/'
},
devServer: {
contentBase: path.resolve(__dirname, 'build'),
port: 4000,
hot: true,
},
resolve: {
extensions: [".*",".js", ".jsx", ".css"],
fallback: {
stream: false
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: ["babel-loader"],
},
{
test: /\.css$/,
exclude: /\.module\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.module\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: { importLoaders: 2, modules: true },
},
"postcss-loader",
],
},
{
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
use: [
{
loader: "url-loader",
options: {
limit: 8192,
},
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve('./index.html')
}),
new CleanWebpackPlugin(),
new HtmlWebpackInjectPreload({
files: [
{
match: /.*\.woff2$/,
attributes: { as: "font", type: "font/woff2", crossorigin: true },
},
{
match: /\.[a-z-0-9]*.css$/,
attributes: { as: "style" },
},
],
}),
],
};
The attached bundle image also gets larger up to 19MB. What's going wrong I'm not able to figure out.
I've recently developed a react + webpack application that is deployed using
AWS Amplify. I've been getting a strange error that is logged on Sentry, but can't
find a way to replicate the bug.
RuntimeError: memory access out of bounds
I suspect it has something to do with my webpack configuration, but I don't know whats wrong.
I never used wasm, but it seems to be related to it.
Here is my production level webpack configuration.
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const env = require('../environment/prod.env');
const commonPaths = require('./paths');
const webpack = require('webpack');
const SentryWebpackPlugin = require('#sentry/webpack-plugin');
module.exports = {
mode: 'production',
devtool: 'source-map',
output: {
filename: `${commonPaths.jsFolder}/[name].[hash].js`,
path: commonPaths.outputPath,
chunkFilename: `${commonPaths.jsFolder}/[name].[chunkhash].js`,
},
optimization: {
minimizer: [
new TerserPlugin({
parallel: true,
cache: true,
sourceMap: true,
}),
new OptimizeCSSAssetsPlugin(),
],
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'initial',
},
async: {
test: /[\\/]node_modules[\\/]/,
name: 'async',
chunks: 'async',
minChunks: 4,
},
},
},
runtimeChunk: true,
},
module: {
rules: [
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
],
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env': env,
}),
new MiniCssExtractPlugin({
filename: `${commonPaths.cssFolder}/[name].css`,
chunkFilename: `${commonPaths.cssFolder}/[name].css`,
}),
],
};
Here is also my common webpack configuration
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const commonPaths = require('./paths');
module.exports = {
context: commonPaths.srcPath,
entry: commonPaths.entryPath,
output: {
path: commonPaths.outputPath,
filename: 'js/[name].js',
},
resolve: {
extensions: ['.ts', '.js', '.html', '.vue'],
alias: {
'~': commonPaths.srcPath,
},
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
include: commonPaths.srcPath,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
plugins: ['react-hot-loader/babel'],
},
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'assets/img/[name].[hash:8].[ext]',
publicPath: '/',
},
},
],
},
{
test: /\.(mp3)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'assets/audio/[name].[hash:8].[ext]',
publicPath: '/',
},
},
],
},
{
test: /\.(ttc|ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'file-loader',
options: {
name: 'assets/fonts/[name].[hash:8].[ext]',
publicPath: '/',
},
},
],
},
],
},
serve: {
content: commonPaths.entryPath,
dev: {
publicPath: commonPaths.outputPath,
},
open: true,
},
resolve: {
modules: ['src', 'node_modules', 'bower_components', 'shared', '/shared/vendor/modules'],
extensions: ['*', '.js', '.jsx'],
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({
favicon: './icon.png',
template: commonPaths.templatePath,
}),
new ScriptExtHtmlWebpackPlugin({
defaultAttribute: 'async',
}),
],
};
Any help would really help. Thanks.
Try to restart your server and make sure you reinstall node modules.
My webpack config file for dev mode
when i am starting node server in dev mode
multiple requests(eg: http://localhost:8090/sockjs-node/563/14x42n5e/xhr_streaming?t=1578560165901) are hitting to the server
this is happing on dev mode, not in prod build
I am guessing this is happening because of hot reload option
const path = require('path');
const autoprefixer = require('autoprefixer');
const webpack = require('webpack');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const { ReactLoadablePlugin } = require('react-loadable/webpack');
const ErrorOverlayPlugin = require('error-overlay-webpack-plugin');
const DashboardPlugin = require('webpack-dashboard/plugin');
const { getAppEnv } = require('./env');
const env = getAppEnv();
const { PUBLIC_URL = '' } = env.raw;
const resolvePath = relativePath => path.resolve(__dirname, relativePath);
module.exports = {
mode: 'development',
devtool: 'cheap-module-source-map',
entry: [
'webpack-hot-middleware/client?path=/__webpack_hmr&reload=true',
resolvePath('../src/index.js')
],
output: {
path: resolvePath('../build'),
filename: '[name].bundle.js',
chunkFilename: '[name].chunk.js',
publicPath: PUBLIC_URL + '/'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter
},
loader: 'eslint-loader'
}
],
include: resolvePath('../src')
},
{
test: /\.(js|jsx)$/,
include: resolvePath('../src'),
loader: 'babel-loader',
options: {
cacheDirectory: true
}
},
{
test: /\.(eot|otf|ttf|woff|woff2)$/,
use: 'file-loader'
},
{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {
// Inline files smaller than 10 kB
limit: 10 * 1024,
noquotes: true
}
}
]
},
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
// Inline files smaller than 10 kB
limit: 10 * 1024
}
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
enabled: false
// NOTE: mozjpeg is disabled as it causes errors in some Linux environments
// Try enabling it in your environment by switching the config to:
// enabled: true,
// progressive: true,
},
gifsicle: {
interlaced: false
},
optipng: {
optimizationLevel: 7
},
pngquant: {
quality: '65-90',
speed: 4
}
}
}
]
},
{
test: /\.s?css$/,
exclude: [resolvePath('../src/styles')],
use: [
'style-loader',
{
loader: 'css-loader',
options: {
// camelCase: true,
// modules: true
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
// browsers: ['last 2 versions', 'not ie < 11'],
flexbox: 'no-2009'
})
]
}
},
'sass-loader',
'import-glob-loader'
]
},
{
test: /\.s?css$/,
include: [resolvePath('../src/styles')],
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
// browsers: ['last 2 versions', 'not ie < 11'],
flexbox: 'no-2009'
})
]
}
},
'sass-loader',
'import-glob-loader'
]
}
]
},
plugins: [
new webpack.DefinePlugin(env.forWebpackDefinePlugin),
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new LodashModuleReplacementPlugin(),
new ErrorOverlayPlugin(),
new DashboardPlugin(),
new ReactLoadablePlugin({
filename: 'build/react-loadable.json'
})
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty'
}
};
screenshots...
Please tell me, here is the config.js file in it, the exported variable with a reference to the API, but there is an API for the dev version, and there is a separate API for the prod version, as I understand it, you need to make 2 separate files, but how to make it in webpack so that when dev he used one file, and prod another?
Below added webpack configuration files, a project on react.js (if that makes any difference :) )
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;
You can define two different npm scripts and use the --config flag for custom files (/file-paths):
"build:dev": "webpack --config ./webpack.client.dev.js",
"build:prod": "webpack --config ./webpack.client.prod.js"
For the common you have to use webpack-merge, for example:
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
...
});
I have an application SPA working correctly, then I need to change the meta tag in order to share the site with og:meta. After a lot of researches, I know that I need to render my content into the server, so my application will be a universal application (server + client renders). I tried to create a simple server, then added a bit code to webpack config. But I got stuck in there. Here is my webpage config:
webpack.config.dev.js
'use strict';
const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const getClientEnvironment = require('./env');
const paths = require('./paths');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
// Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/';
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
const publicUrl = '';
const env = getClientEnvironment(publicUrl);
const client = {
devtool: 'cheap-module-source-map',
entry: [
require.resolve('./polyfills'),
require.resolve('react-dev-utils/webpackHotDevClient'),
paths.appIndexJs,
],
output: {
pathinfo: true,
filename: 'static/js/bundle.js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
},
resolve: {
modules: ['node_modules', paths.appNodeModules].concat(
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: [
'.mjs',
'.web.ts',
'.ts',
'.web.tsx',
'.tsx',
'.web.js',
'.js',
'.json',
'.web.jsx',
'.jsx',
],
alias: {
'react-native': 'react-native-web',
},
plugins: [
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
new TsconfigPathsPlugin({ configFile: paths.appTsConfig }),
],
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.(js|jsx|mjs)$/,
loader: require.resolve('source-map-loader'),
enforce: 'pre',
include: paths.appSrc,
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
compact: true,
},
},
{
test: /\.(ts|tsx)$/,
include: paths.appSrc,
use: [
{
loader: require.resolve('ts-loader'),
options: {
// disable type checker - we will use it in fork plugin
transpileOnly: true,
},
},
],
},
{
test: /\.css$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
],
},
{
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
],
},
],
},
plugins: [
new InterpolateHtmlPlugin(env.raw),
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
new webpack.NamedModulesPlugin(),
new webpack.DefinePlugin(env.stringified),
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new ForkTsCheckerWebpackPlugin({
async: false,
watch: paths.appSrc,
tsconfig: paths.appTsConfig,
tslint: paths.appTsLint,
}),
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
performance: {
hints: false,
},
}
/* i add a bit code to config server rendering */
const nodeExternals = require('webpack-node-externals');
const server = {
target: 'node',
externals: [nodeExternals()],
entry: [
paths.appServerJs,
],
output: {
pathinfo: true,
filename: 'static/js/bundle.js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
},
module: {
rules: [
{
test: /\.(js|jsx|mjs)$/,
loader: require.resolve('source-map-loader'),
enforce: 'pre',
include: paths.appSrc,
},
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
compact: true,
},
},
// Compile .tsx?
{
test: /\.(ts|tsx)$/,
include: paths.appSrc,
use: [
{
loader: require.resolve('ts-loader'),
options: {
// disable type checker - we will use it in fork plugin
transpileOnly: true,
},
},
],
},
],
},
plugins: [
new InterpolateHtmlPlugin(env.raw),
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
],
}
module.exports = [client, server]
server.tsx
import express from 'express';
const port = 3000;
const server = express();
server.use(express.static('dist'));
server.get('/', (req, res) => {
res.send("hello world");
})
server.listen(3000, () => console.log('Example app listening on port 3000!'));
const client works correctly.
But when I try module.exports = [client, server] I got this error
Cannot read property 'publicPath' of undefined.
Is my config correct? Does anyone have some example config?
I don't see publicPath being defined anywhere. Might it be this?