尝试在生产模式下编译时,webpack失败

时间:2019-01-24 13:48:24

标签: node.js reactjs webpack jqxwidgets

我一直在使用React 16.x.x和Jqwidgets 6.2.0和React Boilerplate 3.7.0。我的整个项目都以自己的webpack配置安装在React Boilerplate支架上。我将jqwigets-scripts设置为npm依赖项,并尝试通过在某些github中阅读的正则表达式排除node_modules,但包括jqwidgets-scripts/jqwidgets-react。这是我当前的webpack.base.babel.js文件:

...
 module: {
    rules: [
      {
        test: /\.js$/, // Transform all .js files required somewhere with Babel
        exclude: /node_modules\/(?!(jqwidgets-scripts\/jqwidgets-react)\/).*/,
        use: {
          loader: 'babel-loader',
          options: options.babelQuery,
         },
       },
...

在这种配置下,webpack编译时不会发出警告,也不会出现任何错误(例如超级按钮),即npm start。如果我说npm run-script build,那么大的事情就登台了,如果这样的话,它会抱怨:

Hash: 7b0feef0f8bbac0c9421                                                           
Version: webpack 4.27.1
Time: 41489ms
Built at: 2019-01-24 08:13:05
 251 assets
Entrypoint main = runtime~main.43b100be02c6a9dbfc5a.js vendor.4d1e1f30cd3a7c98cfd8.chunk.js main.5ce13ffd96704eeb6b0d.chunk.js

ERROR in ./node_modules/jqwidgets-scripts/jqwidgets-react/react_jqxgrid.js 1216:12
Module parse failed: Unexpected token (1216:12)
You may need an appropriate loader to handle this file type.
|     render() {
|         return (
>             <div id={this.state.id}>{this.props.value}{this.props.children}</div>
|         )
|     };
 @ ./app/modules/MyModule_1/index.js 43:0-70 954:37-44
 @ ./app/modules/MyModule_2/Loadable.js
 @ ./app/modules/MyModule_3/_nav.js
 @ ./app/modules/MyModule_4/index.js
 @ ./app/modules/MyModule_5/Loadable.js
 @ ./app/containers/MainLayout/_nav.js
 @ ./app/containers/MainLayout/index.js
 @ ./app/containers/MainLayout/Loadable.js
 @ ./app/containers/App/index.js
 @ ./app/app.js
 @ multi ./node_modules/react-app-polyfill/ie11.js ./app/app.js

我尝试按照官方jqwidgets页面(https://www.jqwidgets.com/community/topic/webpack-module-parse-failed/)中的建议更改Webpack配置,如下所示:

 module: {
    rules: [
      {
        test: /\.js$/,
        exclude: '/node_modules',
        include: '/node_modules/jqwidgets-scripts/jqwidgets-react',
        use: {
          loader: 'babel-loader',
          options: options.babelQuery
        }
      },

然后在运行npm start时抱怨的是这样:

webpack built be60767d46a99fe48e6b in 1353ms
✖ 「wdm」: 
ERROR in ./app/app.js 80:4
Module parse failed: Unexpected token (80:4)
You may need an appropriate loader to handle this file type.
| const render = messages => {
|   ReactDOM.render(
>     <AppContainer>
|       <Provider store={store}>
|         <LanguageProvider messages={messages}>
 @ multi ./node_modules/react-app-polyfill/ie11.js webpack-hot-middleware/client?reload=true ./app/app.js main[2]

另外,这是我的babel.config.js

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        modules: false,
      },
    ],
    '@babel/preset-react',
  ],
  plugins: [
    'styled-components',
    '@babel/plugin-proposal-export-namespace-from',
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-syntax-dynamic-import',
  ],
  env: {
    production: {
      only: ['app'],
      plugins: [
        'lodash',
        'transform-react-remove-prop-types',
        '@babel/plugin-transform-react-inline-elements',
        '@babel/plugin-transform-react-constant-elements',
      ],
    },
    test: {
      plugins: [
        '@babel/plugin-transform-modules-commonjs',
        'dynamic-import-node',
      ],
    },
  },
};

我的package.json

{
  "name": "react-boilerplate",
  "version": "3.7.0",
  "description": "A highly scalable, offline-first foundation with the best DX and a focus on performance and best practices",
  "repository": {
    "type": "git",
    "url": "git://github.com/react-boilerplate/react-boilerplate.git"
  },
  "engines": {
    "npm": ">=5",
    "node": ">=8.10.0"
  },
  "author": "Max Stoiber",
  "license": "MIT",
  "scripts": {
    "analyze:clean": "rimraf stats.json",
    "preanalyze": "npm run analyze:clean",
    "analyze": "node ./internals/scripts/analyze.js",
    "extract-intl": "node ./internals/scripts/extract-intl.js",
    "npmcheckversion": "node ./internals/scripts/npmcheckversion.js",
    "preinstall": "npm run npmcheckversion",
    "prebuild": "npm run build:clean",
    "build": "cross-env NODE_ENV=production webpack --config internals/webpack/webpack.prod.babel.js --color -p --progress --hide-modules --display-optimization-bailout",
    "build:clean": "rimraf ./build",
    "start": "cross-env NODE_ENV=development env-cmd .env node server",
    "start:tunnel": "cross-env NODE_ENV=development ENABLE_TUNNEL=true node server",
    "start:production": "npm run test && npm run build && npm run start:prod",
    "start:prod": "cross-env NODE_ENV=production node server",
    "presetup": "npm i chalk shelljs",
    "setup": "node ./internals/scripts/setup.js",
    "clean": "shjs ./internals/scripts/clean.js",
    "clean:all": "npm run analyze:clean && npm run test:clean && npm run build:clean",
    "generate": "plop --plopfile internals/generators/index.js",
    "lint": "npm run lint:js",
    "lint:css": "stylelint './app/**/*.js'",
    "lint:eslint": "eslint --ignore-path .gitignore --ignore-pattern internals/scripts",
    "lint:eslint:fix": "eslint --ignore-path .gitignore --ignore-pattern internals/scripts --fix",
    "lint:js": "npm run lint:eslint -- . ",
    "lint:staged": "lint-staged",
    "pretest": "npm run test:clean && npm run lint",
    "test:clean": "rimraf ./coverage",
    "test": "cross-env NODE_ENV=test jest --coverage",
    "test:watch": "cross-env NODE_ENV=test jest --watchAll",
    "coveralls": "cat ./coverage/lcov.info | coveralls",
    "prettify": "prettier --write"
  },
  "lint-staged": {
    "*.js": [
      "npm run lint:eslint:fix",
      "git add --force"
    ],
    "*.json": [
      "prettier --write",
      "git add --force"
    ]
  },
  "pre-commit": "lint:staged",
  "resolutions": {
    "babel-core": "7.0.0-bridge.0"
  },
  "dependencies": {
    "@coreui/coreui": "^2.1.4",
    "@coreui/coreui-plugin-chartjs-custom-tooltips": "^1.2.0",
    "@coreui/icons": "^0.3.0",
    "@coreui/react": "^2.1.1",
    "ajv": "^6.6.1",
    "babel-polyfill": "^6.26.0",
    "block-ui": "^2.70.1",
    "bootstrap": "^4.1.3",
    "chalk": "^2.4.1",
    "chart.js": "^2.7.3",
    "classnames": "^2.2.6",
    "compression": "^1.7.3",
    "connected-react-router": "^4.5.0",
    "core-js": "^2.6.0",
    "env-cmd": "^8.0.2",
    "exports-loader": "^0.7.0",
    "flag-icon-css": "^3.2.1",
    "font-awesome": "^4.7.0",
    "fontfaceobserver": "2.0.13",
    "history": "^4.7.2",
    "hoist-non-react-statics": "3.0.1",
    "immutable": "^3.8.2",
    "intl": "^1.2.5",
    "invariant": "^2.2.4",
    "ip": "^1.1.5",
    "is-url-external": "^1.0.3",
    "isnumeric": "^0.3.3",
    "jquery": "^3.3.1",
    "jqwidgets-scripts": "^6.2.0",
    "loadable-components": "^2.2.3",
    "lodash": "^4.17.11",
    "minimist": "1.2.0",
    "moment": "^2.22.2",
    "numeral": "^2.0.6",
    "prop-types": "^15.6.2",
    "react": "^16.6.3",
    "react-chartjs-2": "^2.7.4",
    "react-dom": "^16.6.3",
    "react-helmet": "^5.2.0",
    "react-hot-loader": "^4.6.3",
    "react-intl": "^2.7.2",
    "react-loadable": "^5.5.0",
    "react-redux": "^5.1.1",
    "react-router-dom": "^4.3.1",
    "react-sizeme": "^2.5.2",
    "reactstrap": "^6.5.0",
    "redux": "^4.0.1",
    "redux-immutable": "^4.0.0",
    "redux-saga": "^0.16.2",
    "reselect": "4.0.0",
    "resize-sensor": "0.0.6",
    "sanitize.css": "4.1.0",
    "simple-line-icons": "^2.4.1",
    "styled-components": "^4.1.2",
    "warning": "^4.0.2"
  },
  "devDependencies": {
    "@babel/cli": "7.1.2",
    "@babel/core": "7.1.2",
    "@babel/plugin-proposal-class-properties": "7.1.0",
    "@babel/plugin-proposal-export-namespace-from": "^7.2.0",
    "@babel/plugin-syntax-dynamic-import": "7.0.0",
    "@babel/plugin-transform-modules-commonjs": "7.1.0",
    "@babel/plugin-transform-react-constant-elements": "7.0.0",
    "@babel/plugin-transform-react-inline-elements": "7.0.0",
    "@babel/polyfill": "^7.0.0",
    "@babel/preset-env": "7.1.0",
    "@babel/preset-react": "7.0.0",
    "@babel/register": "7.0.0",
    "add-asset-html-webpack-plugin": "3.1.1",
    "babel-core": "7.0.0-bridge.0",
    "babel-eslint": "10.0.1",
    "babel-loader": "8.0.4",
    "babel-plugin-dynamic-import-node": "2.2.0",
    "babel-plugin-lodash": "3.3.4",
    "babel-plugin-react-intl": "3.0.1",
    "babel-plugin-react-transform": "3.0.0",
    "babel-plugin-styled-components": "1.8.0",
    "babel-plugin-transform-react-remove-prop-types": "0.4.19",
    "circular-dependency-plugin": "5.0.2",
    "compare-versions": "3.4.0",
    "compression-webpack-plugin": "2.0.0",
    "copy-webpack-plugin": "^4.6.0",
    "coveralls": "3.0.2",
    "cross-env": "^5.2.0",
    "css-loader": "1.0.0",
    "enzyme": "3.7.0",
    "enzyme-adapter-react-16": "1.6.0",
    "enzyme-to-json": "3.3.4",
    "eslint": "5.7.0",
    "eslint-config-airbnb": "17.1.0",
    "eslint-config-airbnb-base": "13.1.0",
    "eslint-config-prettier": "3.1.0",
    "eslint-import-resolver-webpack": "0.10.1",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-jsx-a11y": "6.1.2",
    "eslint-plugin-prettier": "3.0.0",
    "eslint-plugin-react": "7.11.1",
    "eslint-plugin-redux-saga": "0.9.0",
    "express": "^4.16.4",
    "file-loader": "2.0.0",
    "html-loader": "0.5.5",
    "html-webpack-plugin": "3.2.0",
    "http-proxy-middleware": "^0.19.1",
    "image-webpack-loader": "^4.6.0",
    "imports-loader": "0.8.0",
    "jest-cli": "23.6.0",
    "jest-styled-components": "6.2.2",
    "lint-staged": "7.3.0",
    "ngrok": "3.1.0",
    "node-plop": "0.16.0",
    "node-sass": "^4.11.0",
    "null-loader": "0.1.1",
    "offline-plugin": "5.0.5",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "plop": "2.1.0",
    "pre-commit": "1.2.2",
    "prettier": "1.14.3",
    "react-app-polyfill": "0.1.3",
    "react-test-renderer": "16.6.0",
    "rimraf": "2.6.2",
    "sass-loader": "^7.1.0",
    "shelljs": "^0.8.3",
    "style-loader": "0.23.1",
    "stylelint": "9.6.0",
    "stylelint-config-recommended": "2.1.0",
    "stylelint-config-styled-components": "0.1.1",
    "stylelint-processor-styled-components": "1.5.0",
    "svg-url-loader": "2.3.2",
    "terser-webpack-plugin": "1.1.0",
    "uglifyjs-webpack-plugin": "^2.0.1",
    "url-loader": "1.1.2",
    "webpack": "^4.27.1",
    "webpack-cli": "^3.1.2",
    "webpack-dev-middleware": "3.4.0",
    "webpack-hot-middleware": "2.24.3 ",
    "webpack-pwa-manifest": "3.7.1",
    "whatwg-fetch": "3.0.0"
  }
}

我的webpack.prod.babel.js

// Important modules this config uses
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackPwaManifest = require('webpack-pwa-manifest');
const OfflinePlugin = require('offline-plugin');
const { HashedModuleIdsPlugin } = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = require('./webpack.base.babel')({
  mode: 'production',

  // In production, we skip all hot-reloading stuff
  entry: [
    require.resolve('react-app-polyfill/ie11'),
    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',
  },

  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          warnings: false,
          compress: {
            comparisons: false,
          },
          parse: {},
          mangle: true,
          output: {
            comments: false,
            ascii_only: true,
          },
        },
        parallel: true,
        cache: true,
        sourceMap: true,
      }),
    ],
    nodeEnv: 'production',
    sideEffects: true,
    concatenateModules: true,
    splitChunks: {
      chunks: 'all',
      minSize: 30000,
      minChunks: 1,
      maxAsyncRequests: 10,
      maxInitialRequests: 3,
      name: true,
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
        },
        main: {
          chunks: 'all',
          minChunks: 2,
          reuseExistingChunk: true,
          enforce: true,
        },
      },
    },
    runtimeChunk: true,
  },

  plugins: [
    // 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,
    }),

    // 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: '/',
      appShell: '/',

      // 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,
    }),

    new CompressionPlugin({
      algorithm: 'gzip',
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0.8,
    }),

    new WebpackPwaManifest({
      name: 'React Boilerplate',
      short_name: 'React BP',
      description: 'My React Boilerplate-based project!',
      background_color: '#fafafa',
      theme_color: '#b1624d',
      inject: true,
      ios: true,
      icons: [
        {
          src: path.resolve('app/images/icon-512x512.png'),
          sizes: [72, 96, 128, 144, 192, 384, 512],
        },
        {
          src: path.resolve('app/images/icon-512x512.png'),
          sizes: [120, 152, 167, 180],
          ios: true,
        },
      ],
    }),

    new HashedModuleIdsPlugin({
      hashFunction: 'sha256',
      hashDigest: 'hex',
      hashDigestLength: 20,
    }),
  ],

  performance: {
    assetFilter: assetFilename =>
      !/(\.map$)|(^(main\.|favicon\.))/.test(assetFilename),
  },
});

我的webpack.dev.babel.js

/**
 * DEVELOPMENT WEBPACK CONFIGURATION
 */

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');

module.exports = require('./webpack.base.babel')({
  mode: 'development',

  // Add hot reloading in development
  entry: [
    require.resolve('react-app-polyfill/ie11'),
    'webpack-hot-middleware/client?reload=true',
    path.join(process.cwd(), 'app/app.js'), // Start with js/app.js
  ],

  // Don't use hashes in dev mode for better performance
  output: {
    filename: '[name].js',
    chunkFilename: '[name].chunk.js',
  },

  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },

  // Add development plugins
  plugins: [
    new webpack.HotModuleReplacementPlugin(), // Tell webpack we want hot reloading
    new HtmlWebpackPlugin({
      inject: true, // Inject all files that are generated by webpack, e.g. bundle.js
      template: 'app/index.html',
    }),
    new CircularDependencyPlugin({
      exclude: /a\.js|node_modules/, // exclude node_modules
      failOnError: false, // show a warning when there is a circular dependency
    }),
  ],

  // Emit a source map for easier debugging
  // See https://webpack.js.org/configuration/devtool/#devtool
  devtool: 'eval-source-map',

  performance: {
    hints: false,
  },
});

最后是我的webpack.base.babel.js

/**
 * COMMON WEBPACK CONFIGURATION
 */

const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const config = require('../../server/config');

// Remove this line once the following warning goes away (it was meant for webpack loader authors not users):
// 'DeprecationWarning: loaderUtils.parseQuery() received a non-string value which can be problematic,
// see https://github.com/webpack/loader-utils/issues/56 parseQuery() will be replaced with getOptions()
// in the next major version of loader-utils.'
process.noDeprecation = true;

module.exports = options => ({
  mode: options.mode,
  entry: options.entry,
  output: Object.assign(
    {
      // Compile into js/build.js
      path: path.resolve(process.cwd(), 'build'),
      publicPath: '/',
    },
    options.output,
  ), // Merge with env dependent settings
  optimization: options.optimization,
  module: {
    rules: [
      {
        test: /\.js$|\.jsx$/, // Transform all .js files required somewhere with Babel
        exclude: /node_modules\/(?!(jqwidgets-scripts\/jqwidgets-react)\/).*/,
        use: {
          loader: 'babel-loader',
          options: options.babelQuery,
        },
      },
      // {
      //   test: /\.js$|\.jsx$/,
      //   exclude: '/node_modules',
      //   include: '/jqwidgets-scripts/jqwidgets-react',
      //   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.)
        // for a list of loaders, see https://webpack.js.org/loaders/#styling
        test: /\.scss$/,
        exclude: /node_modules/,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
      {
        // Preprocess 3rd party .css files located in node_modules
        test: /\.css$/,
        include: /node_modules/,
        use: ['style-loader', 'css-loader'],
      },
      {
        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: /\.html$/,
        use: 'html-loader',
      },
      {
        test: /\.(mp4|webm)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10000,
          },
        },
      },
    ],
  },
  plugins: options.plugins.concat([
    // Always expose NODE_ENV to webpack, in order to use `process.env.NODE_ENV`
    // inside your code for any environment checks; Terser will automatically
    // drop any unreachable code.

    /* new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }), */

    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(config.env),
        HOST: JSON.stringify(config.server_host),
        PORT: JSON.stringify(config.server_port)
      },
    }),

    new webpack.NamedModulesPlugin(),
    new CopyWebpackPlugin([{ from: 'static' }]),
  ]),
  resolve: {
    modules: ['node_modules', 'app'],
    extensions: ['.js', '.jsx', '.react.js'],
    mainFields: ['browser', 'jsnext:main', 'main'],
    alias: {
      moment$: 'moment/moment.js',
    },
  },
  devtool: options.devtool,
  target: 'web', // Make web variables accessible to webpack, e.g. window
  performance: options.performance || {},
});

我的问题是,如何配置webpack以便在生产模式下正常工作?

0 个答案:

没有答案