I have a React project that is bundled by Webpack and served up by react_on_rails. In this project I use the Select component from react-select. Everything works as expected when using Webpack 3. After upgrading to Webpack 4, everything also works as expected in development mode. However, when I build in production mode, the Select component from react-select does not have any styling applied to it.
(I don't have enough reputation points to post images so I am going to provide links to the images.)
Here is what the selector looks like when built in development mode.
selector with styling
And here is what the selector looks like when built in production mode.
selector without styling
The reason the styles are not applied is that react-select uses Emotion css-in-js and the css gets injected into the head in stylesheets.
Here is an example in the head when in development mode.
screenshot of stylesheets in the head
These style tags are all absent in the head when in production mode.
I have narrowed it down to the fact that it seems to be caused by the webpack minification step. If I add
optimization: {
minimize: false
}
to my webpack.config.js, then the styles are present when in production mode.
Here's my webpack.config.js without the optimization added:
const webpack = require('webpack');
const pathLib = require('path');
const devBuild = process.env.NODE_ENV !== 'production';
const config = {
entry: [
'es5-shim/es5-shim',
'es5-shim/es5-sham',
'babel-polyfill',
'./app/bundles/analytic',
'./app/bundles/Pulse/startup/registration',
],
output: {
filename: 'webpack-bundle.js',
path: pathLib.resolve(__dirname, '../app/assets/webpack'),
},
devtool: "source-map",
resolve: {
extensions: [".ts", ".tsx", '.js', '.jsx'],
},
plugins: [
new webpack.EnvironmentPlugin({ NODE_ENV: 'development' }),
],
module: {
rules: [
{
test: /travel-info-type.ts/,
use: [{
loader: 'expose-loader',
options: 'TravelInfoType'
}]
},
{
test: /heatmap-getter.ts/,
use: [{
loader: 'expose-loader',
options: 'HeatmapGetter'
}]
},
{
test: /data-hub.ts/,
use: [{
loader: 'expose-loader',
options: 'DataHub'
}]
},
{
test: /exported-functions.js/,
use: [{
loader: 'expose-loader',
options: 'ExportedFunctions'
}]
},
{
test: /analyticsTracker.ts/,
use: [{
loader: 'expose-loader',
options: 'analyticsTracker'
}]
},
{
test: /railsAnalytics.js/,
use: [{
loader: 'expose-loader',
options: 'railsAnalytics'
}]
},
{
test: require.resolve('react'),
use: {
loader: 'imports-loader',
options: {
shim: 'es5-shim/es5-shim',
sham: 'es5-shim/es5-sham',
}
},
},
{
test: /\.(woff|woff2|eot|ttf|svg|gif|png)$/,
use: [{
loader: 'url-loader'
}],
},
{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
},
// All files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'.
{ test: /\.tsx?$/, loader: "ts-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
// Extract css files
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: [ "style-loader", "css-loader", "sass-loader" ],
},
],
},
};
module.exports = config;
if (devBuild) {
console.log('Webpack dev build for Rails'); // eslint-disable-line no-console
module.exports.devtool = 'eval-source-map';
} else {
console.log('Webpack production build for Rails'); // eslint-disable-line no-console
}
And here is my package.json
{
"name": "myProject",
"version": "0.0.1",
"private": true,
"scripts": {
"build:test": "webpack --config webpack.config.js",
"build:production": "NODE_ENV=production webpack --mode=production --config webpack.config.js",
"build:development": "webpack --mode=development -w --config webpack.config.js",
"test": "jest",
"test:watch": "yarn test --watch",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook -o ../public/storybook"
},
"cacheDirectories": [
"node_modules",
"client/node_modules"
],
"dependencies": {
"actioncable": "^5.2.0",
"color-convert": "^1.9.0",
"es5-shim": "^4.5.9",
"expose-loader": "^0.7.3",
"imports-loader": "^0.7.1",
"js-cookie": "^2.2.0",
"moment": "^2.18.1",
"prop-types": "^15.5.7",
"rc-slider": "^8.6.7",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-on-rails": "6.9.3",
"react-onclickoutside": "^5.11.1",
"react-redux": "^6.0.0",
"react-router-dom": "^4.1.1",
"react-select": "^2.3.0",
"react-table": "^6.0.5",
"react-toggle-switch": "^2.1.3",
"react-tooltip": "^3.6.1",
"redux": "^4.0.1",
"redux-batched-actions": "^0.2.0",
"redux-thunk": "^2.3.0",
"rxjs": "5.5.2"
},
"devDependencies": {
"#storybook/addon-knobs": "^3.4.11",
"#storybook/addons": "^3.4.11",
"#storybook/react": "^3.4.11",
"#types/actioncable": "^0.0.2",
"#types/bugsnag": "^2.5.28",
"#types/google-maps": "^3.2.0",
"#types/googlemaps": "^3.26.11",
"#types/highcharts": "^4.2.55",
"#types/jest": "23.3.10",
"#types/jquery": "^2.0.45",
"#types/js-cookie": "^2.2.0",
"#types/lodash": "^4.14.118",
"#types/moment": "^2.13.0",
"#types/rc-slider": "^8.6.3",
"#types/react": "^16.8.1",
"#types/react-dates": "^16.0.5",
"#types/react-dom": "16.0.11",
"#types/react-redux": "^7.0.1",
"#types/react-router": "^4.0.26",
"#types/react-router-dom": "^4.2.7",
"#types/react-select": "^2.0.11",
"#types/react-tooltip": "^3.3.5",
"ts-loader": "^5.3.3",
"babel-cli": "^6.23.0",
"babel-core": "^6.23.1",
"babel-loader": "^7.1.5",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-2": "^6.22.0",
"babel-runtime": "^6.23.0",
"css-loader": "^0.28.0",
"enzyme": "^3.8.0",
"enzyme-adapter-react-16": "^1.9.0",
"highcharts": "^6.0.3",
"jest": "23.3.0",
"jquery": "^3.2.1",
"jsdom": "^10.0.0",
"node-sass": "^4.9.3",
"react-test-renderer": "^16.7.0",
"redux-mock-store": "^1.2.3",
"sass-loader": "^7.1.0",
"sinon": "^2.4.1",
"source-map-loader": "^0.2.1",
"storybook-addon-jsx": "^5.4.0",
"style-loader": "^0.16.1",
"ts-jest": "23.10.5",
"typescript": "^3.0.1",
"url-loader": "^1.1.2",
"webpack": "^4.29.5",
"webpack-cli": "^3.2.3"
}
}
And here is the component that is using the Select component:
import * as React from 'react'
import Select from 'react-select'
import { MultiSelectOption } from '../interfaces/SelectionUI'
class MultipleSelectPicker extends React.PureComponent<MultipleSelectPickerProps> {
onChange = (allSelected: MultiSelectOption[]) => {
const {
onAdd,
onRemove,
values,
} = this.props
if (values.length < allSelected.length) {
const addedOption = allSelected.find(selected => !values.includes(selected))
onAdd(addedOption)
}
else if (values.length > allSelected.length) {
const removedOption = values.find(value => !allSelected.includes(value))
onRemove(removedOption)
}
}
render() {
const {
name,
values,
options,
placeholder,
} = this.props
return (
<Select
name={name}
value={values}
className={`${name} selectpicker`}
options={options}
onChange={this.onChange}
isMulti
placeholder={placeholder}
/>
)
}
}
export interface MultipleSelectPickerProps {
name: string,
options: MultiSelectOption[],
values: MultiSelectOption[],
placeholder?: string,
onAdd: (addedOption: MultiSelectOption) => void,
onRemove: (removedOption: MultiSelectOption) => void,
}
export default MultipleSelectPicker
Anyone have an idea about why the Webpack 4 minimization would keep the react-select Emotion stylesheets from getting injected and how to fix that?
I found a workaround. I swapped out the default webpack minimizer for the (UglifyJsPlugin)[https://github.com/webpack-contrib/uglifyjs-webpack-plugin] and now everything works as expected.
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
optimization: {
minimizer: [ new UglifyJsPlugin() ],
}
Related
I'm trying to create a webpack 5 : babel 7 configuration that transpiles down to es5 that IE11 can read. It's a static site that uses vue.js.
I've got it building successfully, but it's not doing some things that I feel the docs imply should be happening.
The issues I have specifically are
I can't get transform-shorthand-properties to work. After it runs they are still shorthand.
outputs ->
sayHello() { ... }
instead of ->
sayHello : function() { ... }
The docs say that transform-shorthand-properties is part of #babel/preset-env now so I hoped it would work out of the box.
When it didn't, I tried installing the plugin package and listing it in my babel configs plugins array, as shown in the docs above. But that didn't work either.
Another es6 feature that isn't transpiling down to es5 is for...of
I've got my webpack config target set using a browserslist config file.
I'm not sure where I'm going wrong here, and stackoverflow is full of deprecated advice or configs for webpack 2, 3, and 4.
Here are my config files
.browserslistrc
# Browsers that we support
defaults
IE 11
package.json
"dependencies": {
"#babel/polyfill": "^7.12.1",
"#babel/runtime": "^7.18.0",
"#fortawesome/fontawesome-free": "^5.15.3",
"#popperjs/core": "^2.9.2",
"bootstrap": "^4.6.0",
"gyp": "^0.5.0",
"jquery": "^3.6.0",
"n": "^6.8.0",
"node-gyp": "^6.1.0",
"url-search-params-polyfill": "^8.1.1"
},
"optionalDependencies": {
"fsevents": "^2.1.3"
},
"devDependencies": {
"#babel/core": "^7.17.12",
"#babel/plugin-transform-runtime": "^7.18.0",
"#babel/plugin-transform-shorthand-properties": "^7.16.7",
"#babel/preset-env": "^7.17.12",
"#babel/register": "^7.17.7",
"autoprefixer": "^10.4.7",
"babel-loader": "^8.2.5",
"babel-preset-vue": "^2.0.2",
"broken-link-checker": "^0.7.8",
"bufferutil": "^4.0.6",
"canvas": "^2.9.1",
"core-js": "^3.22.5",
"cross-env": "^7.0.3",
"css-loader": "^6.7.1",
"cssnano": "^4.1.11",
"expose-loader": "^4.0.0",
"fs": "0.0.1-security",
"jsdom": "^19.0.0",
"link-check": "^5.1.0",
"mini-css-extract-plugin": "^2.6.0",
"node-linkchecker": "0.0.3",
"popper.js": "^1.16.1",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"precss": "^4.0.0",
"style-loader": "^3.3.1",
"uglifyjs-folder": "^3.1.2",
"utf-8-validate": "^5.0.5",
"vue-loader": "^15.9.8",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.12",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2"
}
webpack.config.json
const path = require('path');
const webpack = require('webpack');
const { VueLoaderPlugin } = require('vue-loader');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const postcssPresetEnv = require('postcss-preset-env');
module.exports = {
entry: './webpack/entry.js',
target: 'browserlist',
devtool: "source-map",
output: {
path: path.resolve(__dirname, "src/assets/javascript/"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
{ loader: 'postcss-loader', options: {
indent: 'postcss',
plugins: () => [ postcssPresetEnv() ]
}
}
]
},
{
test: require.resolve('jquery'),
loader: 'expose-loader',
options: {
exposes: ['$', 'jQuery'],
},
},
{
test: /\.vue$/,
use: { loader: 'vue-loader' }
}
]
},
performance: {
hints: false
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
}),
new VueLoaderPlugin()
]
};
babel.config.json
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": 3,
"targets": {
"chrome": "58",
"ie": "11"
},
"debug": true,
"modules": "commonjs"
},
"vue"
]
],
"plugins": [
"#babel/plugin-transform-runtime",
"#babel/plugin-transform-shorthand-properties"
],
"env": {
"production": {
"presets": ["minify"]
}
},
"ignore": ["node_modules"]
}
entry.js
import 'core-js/actual';
import "regenerator-runtime/runtime";
import 'bootstrap';
import 'jquery';
// some back to top button jquery stuff
Does anybody have any ideas why this might not be working as I'm expecting?
Even more frustratingly, when I copy and paste my problematic 'newsearch.js' file into the babel repl, I am able to see it transform all my shorthand functions and for...of loops without using any packages and setting the browserslist to defaults, ie 11.
For 3 days straight I am having a trouble to setup Webpack for staging purposes.
The goal is to rewrite url of assets in final .css file (frontend.css) like this:
Let's say that in .scss file I have:
background: url('/assets/image.png') (this works for dev and prod)
and in final outputted .css file for staging, I want it to be:
background: url('https://stage.domain.com/staging/project-name/assets/image.png')
I have script npm run stage, that build js. and .css only for staging puposes.
It creates stage dir on root with two files frontened-bundle.js and frontend.css. (see bottom of "Files structure" screenshot).
I tried to rewrite url with resolve-url-loader with root parameter, but I cant get it working.
publicPath is also ignored.
I am not sure what I am doing wrong.
Please point me in right direction.
Files structure:
webpack.stage.js:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const public_path = 'https://stage.domain.com/staging/project-name/'
module.exports = {
context: __dirname,
entry: {
frontend: [
'./src/js/index.js',
'./src/scss/main.scss'
],
// customizer: './src/customizer.js'
},
resolve: {
extensions: ['.ts', '.js', '.jsx', '.scss', '...',],
},
output: {
path: path.resolve(__dirname, 'stage'),
publicPath: public_path,
filename: '[name]-bundle.js'
},
mode: 'production',
// devtool: 'cheap-eval-source-map',
module: {
rules: [
{
enforce: 'pre',
exclude: /node_modules/,
test: /\.jsx$/,
loader: 'eslint-loader'
},
{
test: /\.jsx?$/,
loader: 'babel-loader'
},
{
test: /\.s?css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: public_path,
sourceMap: true
}
},
{
loader: 'css-loader',
options: {
url: false,
sourceMap: true
}
},
{
loader: 'resolve-url-loader',
options: {
// root: path.join(__dirname, './'), // returns url("../../assets/assets/fonts/NewYork.woff2")
// root: '/', // returns url('../../../../../../assets/fonts/NewYork.woff2')
// root: './', // returns url('../../assets/fonts/NewYork.woff2')
attempts: 1,
debug: true,
sourceMap: true,
publicPath: public_path,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
},
]
},
{
test: /\.(ttf|woff|woff2|eot|jpe?g|png|svg|gif)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
// outputPath: '../',
publicPath: publicPath,
},
},
'img-loader',
'url-loader',
]
}
]
},
plugins: [
// new StyleLintPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css'
}),
],
optimization: {
// minimizer: [new UglifyJsPlugin(), new OptimizeCssAssetsPlugin()]
}
};
package.json
{
"name": "project_name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --mode=production",
"dev": "webpack --watch",
"stage": "npm run clean && webpack --config webpack.stage.js -p --progress --profile",
"clean": "rm -rf stage"
},
"repository": {
"type": "git",
"url": ""
},
"keywords": [
"webpack"
],
"author": "",
"license": "ISC",
"bugs": {
"url": ""
},
"homepage": "",
"devDependencies": {
"#babel/cli": "^7.14.5",
"#babel/core": "^7.6.2",
"#babel/preset-env": "^7.6.2",
"autoprefixer": "^9.6.4",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"browser-sync": "^2.27.4",
"browser-sync-webpack-plugin": "^2.2.2",
"css-loader": "^3.2.0",
"css-mqpacker": "^7.0.0",
"eslint": "^6.5.1",
"eslint-config-prettier": "^6.4.0",
"eslint-config-wordpress": "^2.0.0",
"eslint-loader": "^3.0.2",
"eslint-plugin-prettier": "^3.1.1",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^4.2.0",
"img-loader": "^3.0.1",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.14.1",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"prettier": "^1.18.2",
"resolve-url-loader": "^4.0.0",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"stylelint": "^11.0.0",
"stylelint-config-recommended-scss": "^4.0.0",
"stylelint-config-wordpress": "^15.0.0",
"stylelint-order": "^3.1.1",
"stylelint-scss": "^3.11.1",
"stylelint-webpack-plugin": "^1.0.1",
"svg-sprite-loader": "^4.1.6",
"svgo": "^1.3.0",
"svgo-loader": "^2.2.1",
"uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^4.1.1",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"wp-pot-cli": "^1.5.0"
},
"dependencies": {
"#babel/polyfill": "^7.6.0",
"imagemin": "^8.0.0",
"jquery": "^3.6.0"
}
}
I've had this similar issue in the past, I tried the below from the docs,
const ASSET_PATH = process.env.ASSET_PATH || '/';
export default {
output: {
publicPath: ASSET_PATH,
},
plugins: [
// This makes it possible for us to safely use env vars on our code
new webpack.DefinePlugin({
'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH),
}),
],
};
But actually, the one that worked perfectly for my issue is below, while the public path was the CDN link from where the assets were served
require('dotenv').config();
__webpack_public_path__ = config.publicPath // publicPath is process.env.ASSET_PATH || '/';
When you set the publicPath as "../" did you also try the useRelativePaths: true?
Ref:- https://github.com/webpack-contrib/file-loader#userelativepath
Im having a real hard time with this one. I was keen to get into webpack and do a setup from the ground up most of my build is building apart from the section that populates the index.html file. Webpack is throwing an error like so
ERROR in Error: undefined:1
undefine__webpack_require__i/*! !../node_modules/lodash/lodash.js
I also get a similar error with css-loader
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
SyntaxError: Unexpected identifier
at Object../node_modules/css-loader/dist/cjs.js
The odd thing about this error is the start of the path which should be ./node_modules from the location webpack is building from but for some reason its assuming its ../node_modules
The full error is below if anyone could hazard a guess to why this is happening
ERROR in Error: undefined:1
undefine__webpack_require__i/*! !../node_modules/lodash/lodash.js */ "./node_modules/lodash/lodash.js"defined undefined=undefined undefinedrundefinedeundefinedqundefineduundefinediundefinedrundefinedeundef
ined(undefined"undefined!undefined!undefined.undefined.undefined/undefinednundefinedoundefineddundefinedeundefined_undefinedmundefinedoundefineddundefineduundefinedlundefinedeundefinedsundefined/undefinedl
undefinedoundefineddundefinedaundefinedsundefinedhundefined/undefinedlundefinedoundefineddundefinedaundefinedsundefinedhundefined.undefinedjundefinedsundefined"undefined)undefined;undefinedmundefinedoundef
ineddundefineduundefinedlundefinedeundefined.undefinedeundefinedxundefinedpundefinedoundefinedrundefinedtundefinedsundefined undefined=undefined undefinedfundefineduundefinednundefinedcundefinedtundefinedi
undefinedoundefinednundefined undefined(undefinedtundefinedeundefinedmundefinedpundefinedlundefinedaundefinedtundefinedeundefinedPundefinedaundefinedrundefinedaundefinedmundefinedsundefined)
SyntaxError: Unexpected string
- template.html:97 Object../node_modules/html-webpack-plugin/lib/loader.js!./src/template.html
C:/Random_Personal_Projects/experimental_cloud_storage/src/template.html:97:1
- template.html:21 __webpack_require__
C:/Random_Personal_Projects/experimental_cloud_storage/src/template.html:21:30
- template.html:85
C:/Random_Personal_Projects/experimental_cloud_storage/src/template.html:85:18
- template.html:88
C:/Random_Personal_Projects/experimental_cloud_storage/src/template.html:88:10
- index.js:247 HtmlWebpackPlugin.evaluateCompilationResult
[experimental_cloud_storage]/[html-webpack-plugin]/index.js:247:28
- index.js:161
[experimental_cloud_storage]/[html-webpack-plugin]/index.js:161:23
The webpack config looks like so
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: ['babel-polyfill', './src/index.jsx'],
target: 'web',
resolve: {
modules: ['node_modules'],
extensions: ['.js', '.jsx'],
},
output: {
path: path.resolve(__dirname, 'wwwroot'),
filename: 'bundle.js',
publicPath: '/',
},
module: {
rules: [
{
enforce: 'pre',
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'eslint-loader',
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
{
test: /\.svg$/,
loader: 'svg-inline-loader',
},
{
test: /\.json$/,
use: ['json-loader'],
type: 'javascript/auto',
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
fallback: 'file-loader',
name: '[name].[ext]',
outputPath: 'assets/',
publicPath: '/assets/',
},
},
],
},
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
{
loader: 'fast-sass-loader',
options: {
sourceMap: true,
data: '#import "app.scss";',
includePaths: [path.resolve(__dirname, 'src/styles/sass')],
},
},
],
},
],
},
devtool: 'cheap-module-eval-source-map',
plugins: [
new StyleLintPlugin({
syntax: 'scss',
}),
new MiniCssExtractPlugin({
filename: 'style.bundle.css',
}),
new HtmlWebpackPlugin({
template: './src/template.html',
filename: './index.html',
favicon: './src/assets/img/favicon.png',
}),
],
};
My babel config looks like this
module.exports = {
presets: [
[
'#babel/preset-env', {
targets: { esmodules: true },
},
],
'#babel/preset-react',
],
plugins: [
'#babel/plugin-transform-runtime',
'#babel/plugin-proposal-object-rest-spread',
['inline-react-svg', {
svgo: {
plugins: [
{
removeTitle: true,
},
{
removeAttrs: { attrs: '(data-name)' },
},
],
},
}],
],
};
And the package.json looks like this
{
"name": "experimental_cloud_storage",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.4.0",
"#testing-library/user-event": "^7.2.1",
"babel-polyfill": "^6.26.0",
"bootstrap": "^4.4.1",
"firebase": "^7.8.2",
"node-sass": "^4.13.1",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-redux": "^7.2.0",
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.0",
"redux": "^4.0.5",
"redux-persist": "^6.0.0",
"redux-thunk": "^2.3.0",
"sweetalert": "^2.1.2",
"sweetalert2": "^9.7.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"watch": "webpack --config webpack.dev.js --watch"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#babel/core": "^7.6.4",
"#babel/plugin-proposal-object-rest-spread": "^7.6.2",
"#babel/plugin-transform-runtime": "^7.6.2",
"#babel/preset-env": "^7.6.3",
"#babel/preset-react": "^7.6.3",
"autoprefixer": "^8.4.1",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"babel-plugin-inline-react-svg": "^1.1.0",
"babel-plugin-lodash": "^3.3.4",
"copy-webpack-plugin": "^4.6.0",
"css-loader": "^3.2.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"eslint": "^6.5.1",
"eslint-config-airbnb": "^18.0.1",
"eslint-loader": "^3.0.2",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.16.0",
"fast-sass-loader": "^1.5.0",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"jest": "^23.0.0",
"jest-cli": "^23.0.0",
"jest-html-reporter": "^2.5.0",
"jest-localstorage-mock": "^2.4.0",
"jest-teamcity-reporter": "^0.9.0",
"json-loader": "^0.5.7",
"mini-css-extract-plugin": "^0.4.5",
"mock-socket": "^8.0.5",
"node-sass": "^4.11.0",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"postcss-loader": "^2.1.4",
"precss": "^4.0.0",
"react-inlinesvg": "^1.1.7",
"react-svg-loader": "^3.0.3",
"redux-mock-store": "^1.5.4",
"resolve-url-loader": "^3.1.0",
"speed-measure-webpack-plugin": "^1.3.1",
"style-loader": "^0.21.0",
"stylelint": "^9.10.1",
"stylelint-config-airbnb": "0.0.0",
"stylelint-config-recommended-scss": "^3.2.0",
"stylelint-order": "^0.8.1",
"stylelint-scss": "^3.5.4",
"stylelint-webpack-plugin": "^0.10.4",
"svg-inline-loader": "^0.8.0",
"terser-webpack-plugin": "^2.1.3",
"url-loader": "^2.2.0",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"webpack-merge": "^4.2.2",
"webpack-plugin-replace": "^1.2.0"
}
}
Cheers in advance as this one has had me stuck for over an hour with nothing seeming to do the trick from aliasing the modules folder including the modules: ['node_modules'] in the resolve part of the config to a whole variety of different things.
From looking around I think its something to do with the HtmlWebpackPlugin but I could be completely wrong on that one
So after hours of debugging I have finally found what was causing the issue.
when the script strats via npm it calls webpack.dev.js which merges the common setup with the dev setup. i removed all the values from
plugins: [
new ReplacePlugin({
exclude: [
/node_modules/,
/obj/,
/Properties/,
/react/,
/redux/,
/\.js$/,
],
values: {}, <--- here leaving im assuming lodash to freak out as it was trying to merge nothing.
}),
],
After i removed the plugins from that file everything was fine as im again assuming that the plugin wasnt being called with no arguments.
I've updated my webpack file. Now it's won't apply my custom style to the main style bundle. No errors, classes with custom style just missing in bundle.
When I'm running build with development mode - everything is ok and my styles are exist in the bundle. Such happens only with production build.
I tried extract-text-webpack-plugin instead mini-css-extract-plugin but result is same - in prod build my styles are missing.
I'll be very apriciated for any kind of help.
Here is files:
webpack.config.js
const path = require('path');
const fs = require('fs');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const autoprefixer = require('autoprefixer');
const lessToJs = require('less-vars-to-js');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const publicPath = 'public';
const themeVariables = lessToJs(
fs.readFileSync(path.join(__dirname, './assets/style/ant-theme-vars.less'), 'utf8'),
);
module.exports = (env, options) => {
const mode = env ? env.mode : options.mode;
return {
entry: './assets/app.jsx',
output: {
path: path.resolve(__dirname, publicPath),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
},
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: 'last 2 version',
}),
],
},
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true,
modifyVars: themeVariables,
},
},
],
},
{
test: /\.s?css$/,
exclude: [/node_modules/],
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
},
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: 'last 2 version',
}),
],
},
},
{
loader: 'sass-loader',
},
],
},
{
test: /\.jsx?$/,
exclude: [/node_modules/],
loaders: ['babel-loader'],
resolve: { extensions: ['.js', '.jsx'] },
},
{
test: /\.(png|jpg|jpeg|gif|svg|ico)$/,
exclude: [/node_modules/],
use: [
{
loader: 'file-loader',
options: {
name: 'img/[name].[ext',
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 70,
},
},
},
],
},
{
test: /\.(otf|ttf|woff|woff2)$/,
exclude: [/node_modules/],
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]',
},
},
],
},
plugins: [
new CleanWebpackPlugin(publicPath, {}),
new MiniCssExtractPlugin({
filename: 'bundle.css',
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './assets/www/index.html',
}),
],
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
uglifyOptions: {
compress: true,
mangle: true,
warnings: false,
drop_console: true,
unsafe: true,
},
sourceMap: true,
}),
],
},
devServer: {
contentBase: path.join(__dirname),
compress: true,
port: 9000,
publicPath: '/',
historyApiFallback: true,
},
devtool: mode === 'development' ? 'cheap-inline-module-source-map' : '',
};
};
package.json
{
"name": "react-templates",
"version": "1.0.0",
"description": "",
"main": "bundle.js",
"sideEffects": false,
"scripts": {
"build": "webpack --progress --mode production",
"build-dev": "webpack -p --progress --mode development",
"start": "webpack-dev-server --mode production --open",
"eslint": "eslint . --ext .js --ext .jsx",
"stylelint": "stylelint assets/scss",
"deploy-current-branch-dev": "npm run build-dev && firebase deploy",
"deploy-dev": "git checkout -- . && git clean -fd && git checkout develop && git remote update && git pull && npm run build-dev && firebase deploy"
},
"author": "",
"license": "ISC",
"dependencies": {
"antd": "3.8.2",
"autoprefixer": "9.0.1",
"brace": "0.11.1",
"clean-webpack-plugin": "0.1.19",
"extract-text-webpack-plugin": "4.0.0-beta.0",
"fast-async": "^6.3.8",
"file-system": "2.2.2",
"firebase": "5.3.0",
"history": "4.7.2",
"html-webpack-plugin": "^3.2.0",
"less-vars-to-js": "1.3.0",
"lodash": "^4.17.11",
"mini-css-extract-plugin": "^0.4.3",
"moment": "2.22.2",
"optimize-css-assets-webpack-plugin": "5.0.0",
"prop-types": "15.6.2",
"react": "15.6.1",
"react-ace": "6.1.4",
"react-copy-to-clipboard": "5.0.1",
"react-dom": "15.6.1",
"react-favicon": "0.0.14",
"react-redux": "5.0.7",
"react-router": "4.3.1",
"react-router-dom": "4.3.1",
"react-sticky": "^6.0.3",
"redux": "4.0.0",
"redux-devtools-extension": "2.13.5",
"redux-logger": "3.0.6",
"redux-thunk": "2.3.0",
"uglifyjs-webpack-plugin": "^2.0.1",
"webpack": "^4.16.1",
"webpack-merge": "^4.1.4"
},
"devDependencies": {
"#babel/core": "^7.1.2",
"#babel/plugin-proposal-class-properties": "^7.1.0",
"#babel/preset-env": "^7.1.0",
"#babel/preset-react": "^7.0.0",
"babel-eslint": "8.2.6",
"babel-loader": "^8.0.4",
"babel-plugin-import": "^1.9.1",
"css-loader": "1.0.0",
"eslint": "4.19.1",
"eslint-config-airbnb": "17.0.0",
"eslint-plugin-import": "2.12.0",
"eslint-plugin-jsx-a11y": "6.0.3",
"eslint-plugin-react": "7.9.1",
"file-loader": "^2.0.0",
"husky": "1.0.0-rc.13",
"image-webpack-loader": "^4.3.1",
"less": "3.8.1",
"less-loader": "4.1.0",
"node-sass": "4.9.2",
"postcss-loader": "2.1.6",
"sass-loader": "7.0.3",
"style-loader": "0.21.0",
"stylelint": "9.4.0",
"stylelint-config-recommended": "2.1.0",
"webpack-bundle-analyzer": "^3.0.2",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5"
},
"husky": {
"hooks": {
"pre-commit": "npm run eslint && npm run stylelint"
}
}
}
.babelrc
{
"presets": [
"#babel/preset-env",
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-proposal-class-properties",
[
"import",
{
"libraryName": "antd",
"style": true
}
]
]
}
The probplem is sideEffects: false in my package.json file.
I found an issue on Github and there are some issues related to it.
Main reason I did it - I wanted to make a tree shank in my development mode. It worked as I expected but in production mode all my custom styles are missing. To solve this problem I just removed sideEffects: false. So I lost tree shank in dev mode (think it's not good solution to make it in development mode but however).
I want to use the new ES2018 spread operator for objects, and I found that this NPM package should enable it: babel-plugin-transform-object-rest-spread
My package.json:
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"build": "node build/build.js"
},
"dependencies": {
"npm-sass": "^2.2.1",
"vue": "^2.5.13",
"vue-event-hub": "^1.0.2",
"vue2-datepicker": "^1.8.3"
},
"devDependencies": {
"#babel/plugin-proposal-optional-chaining": "^7.0.0-beta.40",
"autoprefixer": "^8.1.0",
"babel-core": "^6.26.0",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.3",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-plugin-transform-vue-jsx": "^3.5.1",
"babel-preset-env": "^1.6.1",
"babel-preset-es2015-node6": "^0.4.0",
"babel-preset-stage-2": "^6.24.1",
"chalk": "^2.3.2",
"copy-webpack-plugin": "^4.5.0",
"css-loader": "^0.28.10",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.11",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^3.0.4",
"node-notifier": "^5.2.1",
"optimize-css-assets-webpack-plugin": "^4.0.0",
"ora": "^2.0.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.1.0",
"postcss-loader": "^2.1.1",
"postcss-url": "^7.3.1",
"rimraf": "^2.6.2",
"semver": "^5.5.0",
"shelljs": "^0.8.1",
"uglifyjs-webpack-plugin": "^1.2.2",
"url-loader": "^1.0.1",
"vue-loader": "^14.1.1",
"vue-style-loader": "^4.0.2",
"vue-template-compiler": "^2.5.13",
"webpack": "^4.1.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-dev-server": "^3.1.0",
"webpack-merge": "^4.1.2"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
And of course in package-lock.json
"babel-plugin-transform-object-rest-spread": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
"integrity": "XXXXXXXXXXX",
"dev": true,
"requires": {
"babel-plugin-syntax-object-rest-spread": "6.13.0",
"babel-runtime": "6.26.0"
}
},
Here is the link to the NPM package: https://www.npmjs.com/package/babel-plugin-transform-object-rest-spread
There isnt much to it, thats why its harder for me to figure out the cause.
I tried installing: babel-preset-es2015-node6, but that didnt help and I tried adding "es2015-node6" to the "presets" in .babelrc, also without any luck.
So now when I try using it, I get an error during the build process:
- invalid expression: Unexpected token ... in
{ ...selected_car, date: state.todays_date.toLocaleDateString()}
This error is cause by this:
<div>
<Car v-if="cars.length > 0" v-for="(car,index) in cars" :key="'car-'+index" :data="{ ...car, date: state.todays_date.toLocaleDateString()}" :selected="false" />
<Car v-if="selected_cars.length > 0" v-for="(selected_car,ind) in selected_cars" :key="'selected-car-'+ind" :data="{ ...selected_car, date: state.todays_date.toLocaleDateString()}" :selected="true"/>
</div>
In the :data attribute of the Car Vue component.
Sorry, I mistakenly delated my .babelrc in my last edit:
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["babel-plugin-transform-es2015-destructuring", "transform-object-rest-spread", "transform-vue-jsx", "transform-runtime"]
}
My webpack.base.conf.js looks like this:
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': resolve('src'),
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('Images/[name].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('Stylesheets/[name].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
In order to use Object rest spread in templates, you need to:
Use Node v8.3+
Configure buble option for vue-loader:
buble: { objectAssign: 'Object.assign' }
If targeting any IE, make sure to include polyfill for Object.assign.
Please use following configuration in your build/vue-loader.conf.js file
var utils = require('./utils')
var config = require('../config')
var isProduction = process.env.NODE_ENV === 'production'
module.exports = {
loaders: utils.cssLoaders({
sourceMap: isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap,
extract: isProduction
}),
transformToRequire: {
video: 'src',
source: 'src',
img: 'src',
image: 'xlink:href'
},
buble: { objectAssign: 'Object.assign' }
}
For more help please use check the same type of issue here.
I have created demo ESNext-In-vue repository for use Object rest spread in Vue templates.
Hopes this will help you !!