This is my current bundle information which i got from bundle analyzer plugin,
Current bundle information
I want to move the jquery to a separate chunk and extract css into a separate single css bundle, is there any other optimization which i can do to reduce my bundle size?
My current webpack is this
webpack.base.js
/**
* COMMON WEBPACK CONFIGURATION
*/
const path = require('path');
const webpack = require('webpack');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
// const BundleAnalyzerPlugin = require('webpack-bundle-
analyzer').BundleAnalyzerPlugin;
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const autoprefixer = require('autoprefixer');
// Remove this line once the following warning goes away (it was meant
webpack loader authors not users):
// 'DeprecationWarning: loaderUtils.parseQuery() received a non-string
value which can be problematic,
be replaced with getOptions()
// in the next major version of loader-utils.'
process.noDeprecation = true;
const environment = require('../../environments/environment');
let publicDeployPath = '/';
const loaderOptions = {};
if (!environment.isLocal) {
publicDeployPath = environment.blobContainerPath;
loaderOptions.root = environment.blobContainerPath;
loaderOptions.minimize = true;
}
module.exports = (options) => ({
entry: options.entry,
output: Object.assign({ // Compile into js/build.js
path: path.resolve(process.cwd(), 'build'),
publicPath: publicDeployPath,
}, options.output), // Merge with env dependent settings
module: {
rules: [
{
test: /\.js$/, // Transform all .js files required somewhere with
Babel
use: {
loader: 'babel-loader',
options: options.babelQuery,
},
},
{
test: /\.jsx$/, // Transform all .js files required somewhere with
Babel
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: options.babelQuery,
},
},
{
// Preprocess our own .css files
// This is the place to add your own loaders (e.g. sass/less etc.)
test: /\.css$/,
// exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader',
options: loaderOptions,
}, {
loader: 'postcss-loader',
options: {
plugins: () => [autoprefixer()],
},
},
] }, true),
},
// {
// // Preprocess 3rd party .css files located in node_modules
// test: /\.css$/,
// include: /node_modules/,
// loader: ExtractTextPlugin.extract({
// fallback: 'style-loader',
// use: [{
// loader: 'css-loader',
// options: loaderOptions,
// },
// ] }, true),
// },
{
test: /\.mp3$/,
loader: 'url-loader?limit=10000&mimetype=audio/mpeg',
options: {
publicPath: publicDeployPath,
},
},
{
test: /\.(eot|svg|otf|ttf|woff|woff2)$/,
loader: 'file-loader',
options: {
publicPath: publicDeployPath,
},
},
{
test: /\.(jpg|png|gif)$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
publicPath: publicDeployPath,
progressive: true,
optimizationLevel: 7,
interlaced: false,
pngquant: {
quality: '65-90',
speed: 4,
},
},
},
],
},
{
test: /\.html$/,
use: 'html-loader',
},
{
test: /\.json$/,
use: 'json-loader',
},
{
test: /\.(mp4|webm)$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
},
},
},
],
},
plugins: options.plugins.concat([
new webpack.ProvidePlugin({
// make fetch available
fetch: 'exports-loader?self.fetch!whatwg-fetch',
}),
// new BundleAnalyzerPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'root.jQuery': 'jquery',
}),
// Always expose NODE_ENV to webpack, in order to use
`process.env.NODE_ENV`
// inside your code for any environment checks; UglifyJS will
automatically
// drop any unreachable code.
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
},
}),
new AddAssetHtmlPlugin({ filepath: path.resolve(process.cwd(),
'app/vendor/VidyoConnector.js'), hash: true }),
new webpack.NamedModulesPlugin(),
]),
resolve: {
modules: ['app', 'node_modules'],
extensions: [
'.js',
'.jsx',
'.react.js',
],
mainFields: [
'browser',
'jsnext:main',
'main',
],
},
devtool: options.devtool,
target: 'web', // Make web variables accessible to webpack, e.g. window
performance: options.performance || {},
node: {
fs: 'empty',
},
});
webpack.production.js
// Important modules this config uses
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const pathsToClean = [
'build',
];
const cleanOptions = {
root: path.resolve(__dirname, '..'),
verbose: true,
dry: false,
allowExternal: true,
};
module.exports = require('./webpack.base.babel')({
// In production, we skip all hot-reloading stuff
entry: [
path.join(process.cwd(), 'app/app.js'),
],
// Utilize long-term caching by adding content hashes (not compilation hashes) to compiled assets
output: {
filename: '[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].chunk.js',
},
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'reactjs',
filename: 'reactjs.[chunkhash].js',
minChunks: (module) => (
// If module has a path, and inside of the path exists the name "somelib",
// and it is used in 3 separate chunks/entries, then break it out into
// a separate chunk with chunk keyname "my-single-lib-chunk", and filename "my-single-lib-chunk.js"
module.resource && (/react/).test(module.resource)
),
}),
new CleanWebpackPlugin(pathsToClean, cleanOptions),
new ExtractTextPlugin({ filename: 'style.[hash].css', disable: false, allChunks: true }),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.[chunkhash].js',
minChunks: (module) => (
// If module has a path, and inside of the path exists the name "somelib",
// and it is used in 3 separate chunks/entries, then break it out into
// a separate chunk with chunk keyname "my-single-lib-chunk", and filename "my-single-lib-chunk.js"
module.context && module.context.includes('node_modules')
),
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
// Minify and optimize the index.html
new HtmlWebpackPlugin({
template: 'app/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
inject: true,
}),
new HtmlWebpackPlugin({ // Also generate a invalid page html
filename: 'ppVideoInvalid.html',
template: 'app/ppVideoInvalid.html',
}),
new HtmlWebpackPlugin({ // Generate a test client html
filename: 'testClient.html',
template: 'app/TestInterface/testClient.html',
}),
],
performance: {
assetFilter: (assetFilename) => !(/(\.map$)|(^(main\.|favicon\.))/.test(assetFilename)),
},
});
Related
I have spent days getting to my current Webpack configuration setup.
When Webpack runs the build, the file size of my minified output file "react_customer.uniqueid.js" ends up being 2.53 MB, I would be satisfied if the file size would be under 1 MB.
Here is a visualization of the bundled JavaScript.
Could this setup be optimized further so the file size gets reduced?
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const nodeExternals = require("webpack-node-externals");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const { EnvironmentPlugin } = require("webpack");
module.exports = {
mode: "production",
entry: {
react_customer: path.resolve(__dirname, "react-customer/index.js"),
react_admin: path.resolve(__dirname, "react-admin/index.js"),
},
output: {
path: path.resolve(__dirname, "production-build"),
filename: "[name].[contenthash].js",
assetModuleFilename: "[name][ext]",
clean: true,
publicPath: "/",
},
//externals: [nodeExternals()],
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
minify: TerserPlugin.uglifyJsMinify,
// `terserOptions` options will be passed to `uglify-js`
// Link to options - https://github.com/mishoo/UglifyJS#minify-options
terserOptions: {},
}),
],
},
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, /*"style-loader",*/ "css-loader"],
},
{ test: /\.(svg|ico|png|webp|jpg|gif|jpeg)$/, type: "asset/resource" },
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [
["#babel/preset-env", { modules: false }],
["#babel/preset-react", { runtime: "automatic" }],
],
},
},
},
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
//"style-loader",
MiniCssExtractPlugin.loader,
// Translates CSS into CommonJS
"css-loader",
// Compiles Sass to CSS
"sass-loader",
],
},
],
},
plugins: [
new EnvironmentPlugin({
backend_server: "https://www.example.com",
frontend_customer: "https://www.example.com",
}),
new BundleAnalyzerPlugin(),
new MiniCssExtractPlugin(),
new HtmlWebpackPlugin({
filename: "index.html",
template: path.resolve(
__dirname,
"server/templates/other/react-customer-template.html"
),
chunks: ["react_customer"],
}),
new HtmlWebpackPlugin({
filename: "admin.html",
template: path.resolve(
__dirname,
"server/templates/other/react-admin-template.html"
),
chunks: ["react_admin"],
}),
],
};
Why my react app fails on production build after upgrading to react 16 ?
After upgrading react to version 16 my app stoped working on production build, when running development works fine. If I downgrade to React 15.6 it still works fine on both prod and dev enviroments.
I am using: "webpack": "^3.5.6", and "react": "^16.0.0",
I am getting the following error:
Uncaught ReferenceError: require is not defined
My webpack prod configuration:
const path = require('path');
const merge = require("webpack-merge");
const webpack = require("webpack");
const config = require("./webpack.base.babel");
const OfflinePlugin = require('offline-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = merge(config, {
// devtool: "nosources-source-map",
devtool: "source-map",
// In production, we skip all hot-reloading stuff
entry: [
'babel-polyfill', // Needed for redux-saga es6 generator support
path.join(process.cwd(), 'src/client/app.js'), // Start with app.js
],
performance: {
assetFilter: (assetFilename) => !(/(\.map$)|(^(main\.|favicon\.))/.test(assetFilename)),
},
plugins: [
new webpack.LoaderOptionsPlugin({
minimize: true
}),
new HtmlWebpackPlugin({
template: "src/client/index.html",
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
inject: true,
}),
// Shared code
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
children: true,
minChunks: 2,
async: true,
}),
// Avoid publishing files when compilation fails
new webpack.NoEmitOnErrorsPlugin(),
// Put it in the end to capture all the HtmlWebpackPlugin's
// assets manipulations and do leak its manipulations to HtmlWebpackPlugin
new OfflinePlugin({
relativePaths: false,
publicPath: '/',
// No need to cache .htaccess. See http://mxs.is/googmp,
// this is applied before any match in `caches` section
excludes: ['.htaccess'],
caches: {
main: [':rest:'],
// All chunks marked as `additional`, loaded after main section
// and do not prevent SW to install. Change to `optional` if
// do not want them to be preloaded at all (cached only when first loaded)
additional: ['*.chunk.js'],
},
// Removes warning for about `additional` section usage
safeToUseOptionalCaches: true,
AppCache: false,
}),
]
});
How can i fix it ?
webpack.base.babel.js
// Common Webpack configuration used by webpack.config.development and webpack.config.production
const path = require("path");
const webpack = require("webpack");
const autoprefixer = require("autoprefixer");
const e2c = require("electron-to-chromium");
const GLOBALS = require('../bin/helpers/globals');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const isProd = process.env.NODE_ENV === 'production';
const postcssLoaderOptions = {
plugins: [
autoprefixer({
browsers: e2c.electronToBrowserList("1.4")
}),
],
sourceMap: !isProd,
};
GLOBALS['process.env'].__CLIENT__ = true;
module.exports = {
target: 'web', // Make web variables accessible to webpack, e.g. window
output: {
filename: 'js/[name].[hash].js',
chunkFilename: 'js/[name].[hash].chunk.js',
path: path.resolve(process.cwd(), 'build'),
publicPath: "/"
},
resolve: {
modules: ["node_modules"],
alias: {
client: path.resolve(process.cwd(), "src/client"),
shared: path.resolve(process.cwd(), "src/shared"),
server: path.resolve(process.cwd(), "src/server")
},
extensions: [".js", '.jsx', ".json", ".scss"],
mainFields: ["browser", "module", 'jsnext:main', "main"],
},
plugins: [
new webpack.NormalModuleReplacementPlugin(
/\/Bundles.js/,
'./AsyncBundles.js'
),
new webpack.IgnorePlugin(/vertx/),
new webpack.ProvidePlugin({
Promise: 'imports-loader?this=>global!exports-loader?global.Promise!es6-promise',
fetch: "imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch", // fetch API
$: "jquery",
jQuery: "jquery",
}),
new webpack.DefinePlugin(GLOBALS),
new ExtractTextPlugin({
filename: "css/[name].[hash].css",
disable: false,
allChunks: true
})
],
module: {
noParse: /\.min\.js$/,
rules: [
// JavaScript / ES6
{
test: /\.(js|jsx)?$/,
include: [
path.resolve(process.cwd(), "src/client"),
path.resolve(process.cwd(), "src/shared"),
],
exclude: /node_modules/,
use: "babel-loader"
},
// Json
{
test: /\.json$/,
use: 'json-loader',
},
//HTML
{
test: /\.html$/,
include: [
path.resolve(process.cwd(), "src/client"),
],
use: [
{
loader: "html-loader",
options: {
minimize: true
}
}
]
},
// Images
// Inline base64 URLs for <=8k images, direct URLs for the rest
{
test: /\.(png|jpg|jpeg|gif|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: "url-loader",
options: {
limit: 8192,
name: "images/[name].[ext]?[hash]"
}
}
},
// Fonts
{
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff'
}
}
},
{
test: /\.(ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader'
},
// Styles
{
test: /\.scss$/,
include: [
path.resolve(process.cwd(), "src/client"),
path.resolve(process.cwd(), "src/shared"),
],
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{
loader: "css-loader",
options: {
sourceMap: true,
modules: true,
importLoaders: 1,
localIdentName: '[local]_[hash:base64:3]'
}
},
{
loader: "postcss-loader",
options: postcssLoaderOptions
},
{
loader: "sass-loader",
options: {
sourceMap: true,
outputStyle: "compressed"
}
}
]
})
},
]
}
};
The fix was rly simple.
I just needed to remove this line noParse: /\.min\.js/
Which does :
Prevent webpack from parsing any files matching the given regular
expression(s). Ignored files should not have calls to import, require,
define or any other importing mechanism.
Updated webpack to the latest version(2.6.1), so the webpack config file, that came with the boilerplate, became outdated...
Looked at the official documentation on migration, but still a bit lost regarding how exactly i need to update my config file:
'use strict';
const path = require('path');
const webpack = require('webpack');
const NODE_ENV = process.env.NODE_ENV;
const SaveAssetsJson = require('assets-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
devtool: '#source-map',
// Capture timing information for each module
profile: false,
// Switch loaders to debug mode
debug: false,
// Report the first error as a hard error instead of tolerating it
bail: true,
entry: [
'babel-polyfill',
'./assets/main.jsx',
],
output: {
path: 'public/dist/',
pathInfo: true,
publicPath: '/dist/',
filename: 'bundle.[hash].min.js',
},
resolve: {
root: path.join(__dirname, ''),
modulesDirectories: [
'web_modules',
'node_modules',
'assets',
'assets/components',
],
extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx'],
},
resolveLoader: {
},
plugins: [
new CleanWebpackPlugin(['public/dist'], {
verbose: true,
dry: false,
}),
new webpack.optimize.UglifyJsPlugin({
minimize: true,
output: {
comments: false,
},
compress: {
warnings: false,
screw_ie8: true,
},
}),
new SaveAssetsJson({
path: process.cwd(),
filename: 'assets.json',
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
],
query: {presets: ['es2015', 'react'] },
module: {
rules: [
{
use: [
"style-loader",
"css-loader",
"autoprefixer-loader",
]
},
{
test: /\.scss$/, // sass files
loader: 'style!css!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded',
},
{
test: /\.(ttf|eot|svg|woff)(\?[a-z0-9]+)?$/, // fonts files
loader: 'file-loader?name=[path][name].[ext]',
},
{
test: /\.jsx?$/, // react files
exclude: /node_modules/,
loaders: ['babel?presets[]=es2015,presets[]=stage-0,presets[]=react'],
include: path.join(__dirname, 'assets'),
},
],
noParse: /\.min\.js/,
}
};
In the end there were few deletion of the deprecated plugin calls and restructuring some of the fields. Here is the 2.6.1 compatible version, the parts of the file that were changed:
'use strict';
module.exports = {
devtool: '#source-map',
// Capture timing information for each module
profile: false,
// Switch loaders to debug mode
//debug: false,
// Report the first error as a hard error instead of tolerating it
bail: true,
entry: [
'babel-polyfill',
'./assets/main.jsx',
],
output: {
path: '/public/dist/', //This has to be an absolute path
publicPath: '/dist/',
filename: 'bundle.[hash].min.js',
},
resolve: {
//merging root and modules
modules: [
path.join(__dirname, ''),
'web_modules',
'node_modules',
'assets',
'assets/components',
],
extensions: [ '.webpack.js', '.web.js', '.js', '.jsx'], //Removed empty entry
},
resolveLoader: {
},
plugins: [
new CleanWebpackPlugin(['public/dist'], {
verbose: true,
dry: false,
}),
new webpack.optimize.UglifyJsPlugin({
minimize: true,
sourceMap: true, //added this
output: {
comments: false,
},
compress: {
warnings: false,
screw_ie8: true,
},
}),
new SaveAssetsJson({
path: process.cwd(),
filename: 'assets.json',
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
],
module: {
//Modules are slightly differently listed now
rules: [
{
test: /\.(css|scss)$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
},
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', "stage-0", 'react']
}
}
}
],
noParse: /\.min\.js/,
}
};
I have tried endlessly to integrate a loader for React-Flexbox-Grid into my web pack config (shown below), but I receive error:
errors — client:119./~/flexboxgrid/dist/flexboxgrid.css
Module parse failed: /Users/---project-path---/node_modules/flexboxgrid/dist/flexboxgrid.css Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
This is the first time I have had to add in something like this, so I am not sure if I have been adding the 'include: /flexboxgrid/' in the correct place (I added it under the development/production rules), but it just returns the same error! Clearly what I am doing is wrong.
ps. I am using react-redux-webpack2-boilerplate
const webpack = require('webpack');
const path = require('path');
const DashboardPlugin = require('webpack-dashboard/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const autoprefixer = require('autoprefixer');
const nodeEnv = process.env.NODE_ENV || 'development';
const isProduction = nodeEnv === 'production';
const jsSourcePath = path.join(__dirname, './source');
const buildPath = path.join(__dirname, './build');
const imgPath = path.join(__dirname, './source/assets/img');
const sourcePath = path.join(__dirname, './source');
if (process.env.NODE_ENV == "production") {
var env = JSON.stringify(require("./production-env.js"));
} else {
var env = JSON.stringify(require("./development-env.js"));
}
// Common plugins
const plugins = [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
filename: 'vendor-[hash].js',
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(nodeEnv),
APPDATA: env,
},
}),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
template: path.join(sourcePath, 'index.html'),
path: buildPath,
filename: 'index.html',
}),
new webpack.LoaderOptionsPlugin({
options: {
postcss: [
autoprefixer({
browsers: [
'last 3 version',
'ie >= 10',
],
}),
],
context: sourcePath,
},
}),
];
// Common rules
const rules = [{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
'babel-loader',
],
},
{
test: /\.(png|gif|jpg|svg)$/,
include: imgPath,
use: 'url-loader?limit=20480&name=assets/[name]-[hash].[ext]',
},
];
if (isProduction) {
// Production plugins
plugins.push(
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false,
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
screw_ie8: true,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true,
},
output: {
comments: false,
},
}),
new ExtractTextPlugin('style-[hash].css')
);
// Production rules
rules.push({
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader!postcss-loader!sass-loader',
}),
});
} else {
// Development plugins
plugins.push(
new webpack.HotModuleReplacementPlugin(),
new DashboardPlugin()
);
// Development rules
rules.push({
test: /\.scss$/,
exclude: /node_modules/,
use: [
'style-loader',
// Using source maps breaks urls in the CSS loader
// https://github.com/webpack/css-loader/issues/232
// This comment solves it, but breaks testing from a local network
// https://github.com/webpack/css-loader/issues/232#issuecomment-240449998
// 'css-loader?sourceMap',
'css-loader',
'postcss-loader',
'sass-loader?sourceMap',
],
});
}
module.exports = {
devtool: isProduction ? 'eval' : 'source-map',
context: jsSourcePath,
entry: {
js: './index.js',
vendor: [
'babel-polyfill',
'es6-promise',
'immutable',
'isomorphic-fetch',
'react-dom',
'react-redux',
'react-router',
'react',
'redux-thunk',
'redux',
],
},
output: {
path: buildPath,
publicPath: '/',
filename: 'app-[hash].js',
},
module: {
rules,
},
resolve: {
extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.js', '.jsx'],
modules: [
path.resolve(__dirname, 'node_modules'),
jsSourcePath,
],
},
plugins,
devServer: {
contentBase: isProduction ? './build' : './source',
historyApiFallback: true,
port: 3000,
compress: isProduction,
inline: !isProduction,
hot: !isProduction,
host: '0.0.0.0',
stats: {
assets: true,
children: false,
chunks: false,
hash: false,
modules: false,
publicPath: false,
timings: true,
version: false,
warnings: true,
colors: {
green: '\u001b[32m',
},
},
},
};
Its better to transform class properties.This kind of loader will help to solve this
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0'],
plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'],
}
}
I use react-boilerplate-3.0 create a mobile project several months ago, and everything worked. But recently when our project is online, I found it not work on android webview when android version < 4.4.
I know android change webview kern after 4.4, so there are some compatibility issues.
I found some issues like
Page load blank on stock Galaxy S3 samsung Android browser
Blank screen, app not hooking into html
and I had fix those;
But there is still have some problem, there is two diff version code:
class AppR1 extends React.Component {...}
import AppR2 from './xxx.js';
const R1 = (<div><AppR1 /></div>)
const R2 = (<div><AppR2 /></div>)
ReactDOM.render(R2, document.getElementById('app'));
When I use npm run start, everything worked, But after I npm run build, my andy(with android 4.2) only work on R1。
So I guess maybe there's some bugs of webpack;
There's no any log been print;
Any tips will be taken seriously:)
Append:
I use "webpack": "2.1.0-beta.8" and "react": "15.0.1",and here is my webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'app');
var BUILD_PATH = path.resolve(ROOT_PATH, 'build');
var NODE_MODULES = path.resolve(ROOT_PATH, 'node_modules');
console.info('*'.repeat(50));
console.info(ROOT_PATH);
console.info('*'.repeat(50));
function isExternal(module) {
var userRequest = module.userRequest;
if (typeof userRequest !== 'string') {
return false;
}
return userRequest.indexOf('bower_components') >= 0 ||
userRequest.indexOf('node_modules') >= 0 ||
userRequest.indexOf('libraries') >= 0;
}
module.exports = {
entry: {
common: ['react','react-dom','react-bootstrap','weishao'],
app: [path.resolve(APP_PATH, 'app.js')]
},
output: {
path: BUILD_PATH,
filename: '[name].[hash].js'
},
module: {
loaders: [{
test: /\.jsx?$/, // Transform all .js files required somewhere with Babel
loader: 'babel',
exclude: /node_modules/,
query: {
presets: [
require.resolve('babel-preset-es2015'),
require.resolve('babel-preset-react'),
require.resolve('babel-preset-stage-0'),
]}
}, {
// Transform our own .css files with PostCSS and CSS-modules
test: /\.css$/,
exclude: /node_modules/,
loader: 'style-loader!css-loader?localIdentName=[local]__[path][name]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader',
//loader: 'style-loader!css-loader?!postcss-loader',
}, {
test: /\.scss$/,
exclude: /node_modules/,
// loaders:ExtractTextPlugin.extract('style','css','sass')
loaders: ['style', 'css', 'sass','postcss'],
}, {
// Do not transform vendor's CSS with CSS-modules
// The point is that they remain in global scope.
// Since we require these CSS files in our JS or CSS files,
// they will be a part of our compilation either way.
// So, no need for ExtractTextPlugin here.
test: /\.css$/,
include: /node_modules/,
loaders: ['style-loader', 'css-loader'],
}, {
test: /\.jpe?g$|\.gif$|\.png$|\.svg$/i,
loader: 'url-loader?name=/images/[hash].[ext]&limit=10000',
//loader: 'file?name=/img/[name].[ext]&limit=10000'
}, {
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file?name=fonts/[name].[hash].[ext]&mimetype=application/font-woff',
}, {
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file?name=fonts/[name].[hash].[ext]&mimetype=application/font-woff',
}, {
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file?name=fonts/[name].[hash].[ext]&mimetype=application/octet-stream',
}, {
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file?name=fonts/[name].[hash].[ext]',
}, {
test: /\.html$/,
loader: 'html-loader',
}, {
test: /\.json$/,
loader: 'json-loader',
}],
},
plugins: [
/*
new webpack.ProvidePlugin({
// make fetch available
fetch: 'exports?self.fetch!whatwg-fetch',
}),
*/
// Always expose NODE_ENV to webpack, in order to use `process.env.NODE_ENV`
// inside your code for any environment checks; UglifyJS will automatically
// drop any unreachable code.
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
},
}),
new webpack.optimize.OccurrenceOrderPlugin(true),
// Merge all duplicate modules
new webpack.optimize.DedupePlugin(),
// Minify and optimize the JavaScript
/*
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false, // ...but do not show warnings in the console (there is a lot of them)
},
}),
*/
//simple copy
new CopyWebpackPlugin([
{ from: require.resolve('weishao/src/static/loading.js'), to: 'loading.js' },
{ from: require.resolve('weishao/src/static/loading.css'), to: 'loading.css' },
{ from: require.resolve('weishao/src/static/loading.png'), to: 'loading.png' },
{ from: require.resolve('weishao/src/whistle.js'), to: 'whistle.js' },
]),
/*
new webpack.DllPlugin({
path: path.join(__dirname,'dist','[name]-manifest.json'),
name: '[name]_library'
}),
*/
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: function(module, count) {
return !isExternal(module) && count >= 2; // adjustable cond
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
chunks: ['common'],
// or if you have an key value object for your entries
// chunks: Object.keys(entry).concat('common')
minChunks: function(module) {
return isExternal(module);
}
}),
/*
new webpack.optimize.MinChunkSizePlugin({
minChunkSize: 1024*1000
}),
*/
new HtmlWebpackPlugin({
template: 'app/index.html',
minify: {
removeComments: false,
collapseWhitespace: false,
removeRedundantAttributes: false,
useShortDoctype: false,
removeEmptyAttributes: false,
removeStyleLinkTypeAttributes: false,
keepClosingSlash: false,
minifyJS: false,
minifyCSS: false,
minifyURLs: false,
},
inject: true
})
],
resolve: {
modules: ['app', 'node_modules'],
extensions: [
'',
'.js',
'.jsx',
'.react.js',
],
},
}