为什么 Webpack 4 缩小会阻止 react-select 组件的样式? [英] Why would Webpack 4 minification prevent styles for react-select component?

查看:58
本文介绍了为什么 Webpack 4 缩小会阻止 react-select 组件的样式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由 Webpack 捆绑并由 react_on_rails 提供的 React 项目.在这个项目中,我使用了 react-select 中的 Select 组件.使用 Webpack 3 时一切正常.升级到 Webpack 4 后,在 development 模式下一切也正常.但是,当我在 production 模式下构建时,react-select 中的 Select 组件没有应用任何样式.

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.)

这是选择器在 development 模式下构建时的样子.

Here is what the selector looks like when built in development mode.

带样式的选择器

这是选择器在 production 模式下构建时的样子.

And here is what the selector looks like when built in production mode.

没有样式的选择器

未应用样式的原因是 react-select 使用了 Emotioncss-in-js 并且 css 被注入到样式表的头部.

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.

这是在 development 模式下的头部示例.

Here is an example in the head when in development mode.

截图头部的样式表

当处于 production 模式时,head 中不存在这些 style 标签.

These style tags are all absent in the head when in production mode.

我已经将范围缩小到它似乎是由 webpack 缩小步骤引起的.如果我添加

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
}

到我的 webpack.config.js,然后样式在 production 模式下出现.

to my webpack.config.js, then the styles are present when in production mode.

这是我的 webpack.config.js,没有添加 optimization:

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
}

这是我的 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"
  }
}

这里是使用 Select 组件的组件:

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

有人知道为什么 Webpack 4 最小化会阻止 react-select 情绪样式表被注入以及如何解决这个问题吗?

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?

推荐答案

我找到了一个解决方法.我为 (UglifyJsPlugin)[https://github 更换了默认的 webpack 最小化器.com/webpack-contrib/uglifyjs-webpack-plugin] 现在一切正常.

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() ],
  }

这篇关于为什么 Webpack 4 缩小会阻止 react-select 组件的样式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆