Skip to content
This repository has been archived by the owner on Mar 3, 2022. It is now read-only.

v1.5.0 not compatible with production builds in webpack #561

Closed
PaulInglis opened this issue May 25, 2018 · 35 comments
Closed

v1.5.0 not compatible with production builds in webpack #561

PaulInglis opened this issue May 25, 2018 · 35 comments
Labels
Milestone

Comments

@PaulInglis
Copy link

The build of our product started failing because it pulled in v1.5.0 of oidc-client.

We've got our package.json set to "oidc-client": "^1.4.1", and it seemed to update it. Clearly it isn't a compatible version (that's what the hat symbolises).

Not sure what has caused it - maybe the move to an optional dependency, but it looks as though the file isn't transpiled in the distributed code.

Here is the output of our logs:

2018-05-25T16:07:33.5570765Z ERROR in js/index-bundle.js from UglifyJs
2018-05-25T16:07:33.5570765Z Unexpected token: name (AccessTokenEvents) [./node_modules/oidc-client/src/AccessTokenEvents.js:9,0][js/index-bundle.js:73144,6]
2018-05-25T16:07:33.5570765Z
2018-05-25T16:07:33.5570765Z ERROR in js/silentRenew-bundle.js from UglifyJs
2018-05-25T16:07:33.5570765Z Unexpected token: name (AccessTokenEvents) [./node_modules/oidc-client/src/AccessTokenEvents.js:9,0][js/silentRenew-bundle.js:8263,6]

@brockallen
Copy link
Member

Bummer -- I had it out as beta for 2+ weeks looking for feedback.

@brockallen
Copy link
Member

Do you have a public repo that I look at to reproduce this issue?

@PaulInglis
Copy link
Author

Sorry bud. Didn't even notice the beta.
I can't share the exact code, but I'll try and reproduce an equivalent

@brockallen
Copy link
Member

That'd be great -- if you can provide me a sample showing how you consume this (i.e. a working 1.4.x version), it'd be a help. Most folks I know only grab the ~/dist file and run from there.

@brockallen
Copy link
Member

@DanielSchaffer -- perhaps something about the change in how we export broke this? Any insight?

@brockallen
Copy link
Member

Related possibly: #562

@DanielSchaffer
Copy link
Contributor

DanielSchaffer commented May 25, 2018

It looks like from the error that their build is pulling in the ES Modules (./node_modules/oidc-client/src/AccessTokenEvents.js) instead of the bundled version. I can't tell what else is going on, but I would think that if the bundler knows to use the module property from package.json, it should be configured to transpile what it finds.

@PaulInglis, what build tool/bundler are you using, what ES level are you targeting, and are you using Babel?

@PaulInglis
Copy link
Author

Webpack 3 and transpiling from ES6

We use the direct import and don't target specific files.

@DanielSchaffer
Copy link
Contributor

Can you share your webpack config?

@PaulInglis
Copy link
Author

Production webpack.config

const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const extractCSS = new ExtractTextPlugin('[name].fonts.css');
const extractSCSS = new ExtractTextPlugin('[name].styles.css');

const BUILD_DIR = path.resolve(__dirname, '../wwwroot');
const SRC_DIR = path.resolve(__dirname, '../src');

console.log('BUILD_DIR', BUILD_DIR);
console.log('SRC_DIR', SRC_DIR);

module.exports = (env = {}) => {
	return {
		entry: {
			index: [SRC_DIR + '/index.js'],
			silentRenew: [SRC_DIR + '/silent_renew/index.js'],
		},
		output: {
			path: BUILD_DIR,
			publicPath: '/',
			filename: 'js/[name]-bundle.js',
			chunkFilename: 'js/[name].[chunkhash].js',
		},
		// watch: true,
		devtool: env.prod ? 'source-map' : 'cheap-module-source-map',
		devServer: {
			contentBase: BUILD_DIR,
			port: 60002,
			historyApiFallback: true,
			compress: true,
			hot: true,
			open: true,
		},
		module: {
			rules: [
				{
					test: /\.(js|jsx)$/,
					exclude: /node_modules/,
					use: {
						loader: 'babel-loader',
						options: {
							cacheDirectory: true,
							presets: ['env', 'stage-0', 'react'],
						},
					},
				},
				/*
				{
					test: /\.js$/,
					exclude: /(node_modules|bower_components)/,
					enforce: 'pre',
					loader: 'eslint-loader',
				},
				*/
				{
					test: /\.html$/,
					loader: 'html-loader',
				},
				{
					test: /\.(scss)$/,
					use: ['css-hot-loader'].concat(extractSCSS.extract({
						fallback: 'style-loader',
						use: [
							{
								loader: 'css-loader',
								options: { include: '../img', alias: { '../img': '../public/img' } },
							},
							{
								loader: 'sass-loader',
							},
						],
					})),
				},
				{
					test: /\.css$/,
					use: extractCSS.extract({
						fallback: 'style-loader',
						use: 'css-loader',
					}),
				},
				{
					test: /\.(png|jpg|jpeg|gif|ico)$/,
					use: [
						{
							// loader: 'url-loader'
							loader: 'file-loader',
							options: {
								name: './img/[name].[hash].[ext]',
							},
						},
					],
				},
				{
					test: /\.(woff(2)?|ttf|eot|otf|svg)(\?v=\d+\.\d+\.\d+)?$/,
					loader: 'file-loader',
					options: {
						name: './fonts/[name].[hash].[ext]',
					},
				}],
		},
		resolve: {
			extensions: ['.js', '.jsx'],
			modules: [
				SRC_DIR,
				'node_modules',
			],
		},
		plugins: [
			new webpack.HotModuleReplacementPlugin(),
			// new webpack.optimize.UglifyJsPlugin({ sourceMap: true }),
			new webpack.NamedModulesPlugin(),
			extractCSS,
			extractSCSS,
			new webpack.DefinePlugin({
				'process.env.NODE_ENV': '"production"',
			}),
			new HtmlWebpackPlugin(
				{
					inject: true,
					template: './public/template.html',
				}
			),
			new HtmlWebpackPlugin({
				template: SRC_DIR + '/silent_renew/silent_renew.html',
				chunks: ['silentRenew'],
				filename: 'silent_renew.html',
			}),
			new CopyWebpackPlugin([
				{ from: './public/img', to: 'img' },
			],
			{ copyUnmodified: false }
			),
			new CopyWebpackPlugin([
				{ from: './public/favicon', to: 'img/favicon' },
			],
			{ copyUnmodified: false }
			),
			new CopyWebpackPlugin([
				{ from: './public/fonts', to: 'fonts' },
			],
			{ copyUnmodified: false }
			),
			new CopyWebpackPlugin([
				{ from: './public/locales', to: 'locales' },
			],
			{ copyUnmodified: false }
			),
		],
	}
};

package.json:

{
  "name": "my-admin-website",
  "version": "1.0.0",
  "description": "My Admin Website",
  "author": "My Team",
  "copyright": "Copyright 2017 Company",
  "license": "MIT",
  "private": true,
  "devDependencies": {
    "accounting": "^0.4.1",
    "babel-core": "^6.26.0",
    "babel-eslint": "^8.2.2",
    "babel-loader": "^7.1.3",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-object-rest-spread": "^6.26.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "bootstrap": "^4.1.1",
    "bootstrap-sweetalert": "^1.0.1",
    "chart.js": "2.7.0",
    "classnames": "^2.2.5",
    "copy-webpack-plugin": "^4.4.2",
    "css-hot-loader": "^1.3.7",
    "css-loader": "^0.28.10",
    "deepmerge": "^2.0.1",
    "enzyme": "^3.3.0",
    "enzyme-adapter-react-16": "^1.1.1",
    "enzyme-to-json": "^3.3.3",
    "eslint": "^4.18.1",
    "eslint-config-airbnb": "^16.1.0",
    "eslint-config-standard": "^11.0.0",
    "eslint-loader": "^2.0.0",
    "eslint-plugin-import": "^2.9.0",
    "eslint-plugin-jsx-a11y": "^6.0.3",
    "eslint-plugin-node": "^6.0.1",
    "eslint-plugin-promise": "^3.6.0",
    "eslint-plugin-react": "^7.7.0",
    "eslint-plugin-standard": "^3.0.1",
    "extract-text-webpack-plugin": "^3.0.2",
    "faker": "^4.1.0",
    "famfamfam-flags": "^1.0.0",
    "file-loader": "^1.1.10",
    "font-awesome": "^4.7.0",
    "formik": "^0.11.11",
    "glyphicons": "^0.2.0",
    "history": "4.7.2",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^2.30.1",
    "i18next": "^10.5.0",
    "i18next-browser-languagedetector": "^2.1.0",
    "i18next-locize-backend": "1.3.0",
    "i18next-react-postprocessor": "^1.0.3",
    "is-url-external": "^1.0.3",
    "jest-css-modules": "^1.1.0",
    "jest-trx-results-processor": "0.0.7",
    "json-server": "^0.12.1",
    "locize-editor": "^1.3.0",
    "lodash": "^4.17.4",
    "lodash.debounce": "^4.0.8",
    "lodash.isequal": "^4.5.0",
    "moment": "^2.20.1",
    "node-sass": "^4.7.2",
    "oidc-client": "^1.4.1",
    "path": "^0.12.7",
    "postcss-color-rebeccapurple": "^3.0.0",
    "postcss-loader": "^2.1.1",
    "promise-alert": "^0.1.1",
    "prop-types": "^15.6.1",
    "raw-loader": "^0.5.1",
    "rc-steps": "^3.1.1",
    "react": "^16.2.0",
    "react-autocomplete": "^1.7.2",
    "react-beautiful-dnd": "^7.1.3",
    "react-bootstrap-button-loader": "^1.0.8",
    "react-bootstrap-toggle": "^2.2.6",
    "react-chartjs-2": "2.7.0",
    "react-code-input": "^3.0.0",
    "react-code-splitting": "^1.2.1",
    "react-color": "^2.14.1",
    "react-css-modules": "4.7.1",
    "react-data-grid": "^3.0.10",
    "react-data-grid-addons": "^3.0.10",
    "react-dates": "^15.4.0",
    "react-dom": "^16.2.0",
    "react-favicon": "^0.0.9",
    "react-helmet": "^5.1.3",
    "react-i18next": "^7.3.0",
    "react-image-gallery": "^0.8.2",
    "react-joyride": "^1.10.1",
    "react-number-format": "^3.3.4",
    "react-maskedinput": "^4.0.0",
    "react-moment-proptypes": "^1.5.0",
    "react-paginate": "^4.4.3",
    "react-redux": "^4.4.5",
    "react-router": "^4.2.0",
    "react-router-bootstrap": "^0.24.2",
    "react-router-dom": "^4.2.2",
    "react-router-redux": "^5.0.0-alpha.6",
    "react-sc": "^0.2.1",
    "react-scripts": "^1.1.0",
    "react-sparklines": "^1.7.0",
    "react-tabtab": "^1.5.0",
    "react-tag-input": "^4.7.3",
    "react-test-renderer": "^16.2.0",
    "react-transition-group": "^2.3.0",
    "react-ultimate-pagination": "^1.2.0",
    "react-user-avatar": "^1.9.0",
    "react-widgets": "^4.1.1",
    "react-with-styles": "^2.3.0",
    "reactstrap": "^5.0.0",
    "recompose": "^0.26.0",
    "redux": "^3.7.2",
    "redux-form": "^7.2.1",
    "redux-logger": "^3.0.6",
    "redux-mock-store": "^1.5.1",
    "redux-oidc": "^3.0.0-beta.16",
    "redux-thunk": "^2.2.0",
    "rimraf": "^2.6.2",
    "rxjs": "^5.5.3",
    "sass-loader": "^6.0.6",
    "simple-line-icons": "^2.4.1",
    "source-list-map": "^2.0.0",
    "style-loader": "^0.19.0",
    "thenby": "^1.2.3",
    "uglify-js": "^3.1.4",
    "universal-cookie": "^2.1.2",
    "url-join": "^3.0.0",
    "url-loader": "^0.6.2",
    "webpack": "^3.10.0",
    "webpack-bundle-analyzer": "^2.11.1",
    "webpack-dev-server": "^2.11.1",
    "why-did-you-update": "^0.1.1",
    "yup": "^0.23.0"
  },
  "jest": {
    "collectCoverage": true,
    "coverageReporters": [
      "json",
      "html",
      "cobertura"
    ],
    "rootDir": "./",
    "roots": [
      "./__tests__",
      "./node_modules"
    ],
    "moduleFileExtensions": [
      "js",
      "jsx",
      "json"
    ],
    "moduleDirectories": [
      "./node_modules",
      "./src"
    ],
    "transformIgnorePatterns": [
      "/node_modules/reactstrap/*.js$"
    ],
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__tests__/mocks/fileTransformer.js",
      "\\.(css)$": "<rootDir>/node_modules/jest-css-modules"
    },
    "setupTestFrameworkScriptFile": "<rootDir>/__tests__/mocks/localStorageMock.js",
    "snapshotSerializers": [
      "enzyme-to-json/serializer"
    ],
    "testResultsProcessor": "<rootDir>/__tests__/processors/jestTrxProcessor"
  },
  "scripts": {
    "dev": "webpack -d --progress --watch --profile --json > compilation-stats.json --env.dev --config ./webpack/webpack.config.dev.js",
    "start": "webpack-dev-server --progress --colors --inline --env.dev --config ./webpack/webpack.config.dev.js",
    "build": "webpack -p --progress --env.prod --config ./webpack/webpack.config.prod.js",
    "clean": "rimraf ./build",
    "test": "jest --testPathPattern=dummy.test.js",
    "refreshVSToken": "vsts-npm-auth -config .npmrc"
  },
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 5.0.0"
  },
  "dependencies": {}
}

@basvis
Copy link

basvis commented May 28, 2018

Similar problem here, when updating to version 1.5.0 it broke the build:

ERROR in common.dbf6d29d468b9c97af24.bundle.js from UglifyJs
Unexpected token: name (OidcClientSettings) [./node_modules/oidc-client/src/OidcClientSettings.js:16,0][common.dbf6d29d468b9c97af24.bundle.js:4602,6]

@xakep139
Copy link

xakep139 commented May 29, 2018

Same problem:

ERROR in main.ab439ba9.js from UglifyJs
Unexpected token: name (SilentRenewService) [./~/oidc-client/src/SilentRenewService.js:6,0][main.ab439ba9.js:345,6]

@xakep139
Copy link

I resolved this error by manually installing latest version of UglifyJS plugin and setting ecma parameter to 6 in uglifyOptions

@brockallen
Copy link
Member

@xakep139 mind showing me what you did, or send a PR?

@xakep139
Copy link

@brockallen, sure! I did the following:

  1. run npm i -D uglifyjs-webpack-plugin or yarn add -D uglifyjs-webpack-plugin
  2. in webpack.config.js replaced new webpack.optimize.UglifyJsPlugin() with
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

//...

plugins: [
  new UglifyJsPlugin({
    uglifyOptions: {
      ecma: 6,  // Default value is "5", so it cause errors
    }
  })
]

@DarkCow
Copy link

DarkCow commented May 29, 2018

@xakep139 You can also upgrade to webpack 4.0, which solves this issue.

edit: webpack 4 already uses the latest version of uglifyjs

@brockallen
Copy link
Member

So @PaulInglis you're not even pulling in the version from ~/lib or ~/dist, right?

@brockallen
Copy link
Member

@DarkCow you seem to follow what's happening here, so mind helping me understand. It sounds like you think by me upgrading to webpack 4 that has caused others still on webpack 3 to see this issue? Or am I missing something.

@PaulInglis
Copy link
Author

@brockallen nope - I'm not even using UglifyJS (see the commented out line in the webpack.config above). It seems to be some internal thing if using the -p flag on webpack.

My work around is to remove the -p, but manually set the production mode via
new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"', }),

@brockallen
Copy link
Member

brockallen commented May 29, 2018

So then I'm still confused... I use webpack (from gulp) to build two versions of this library -- one in ~/lib and one in ~/dist, so if you're not using those then my use of webpack is unrelated to your error in your build using webpack -- I think. right?

So I guess what I'm confused about is what happened in how I'm building/packaging this that affected you? That's why I asked @DanielSchaffer to chime in here, as he had a PR to change how exports are done slightly.

@brockallen
Copy link
Member

brockallen commented May 29, 2018

Actually, I take it back -- "main" points to ~/lib/oidc-client.min.js. So if you're doing a require then that's what you're getting.

@DanielSchaffer
Copy link
Contributor

DanielSchaffer commented May 29, 2018

Hey, sorry, I'm not ignoring the pings ... had a long weekend with the fam, about to start poking now.

The way I understand things, the module property is used by webpack and by default, prioritized ahead of main (see https://webpack.js.org/configuration/resolve/#resolve-mainfields), but I'd expect that it if it does use module, which is meant to be a pointer to an entrypoint for ES Modules, it'd be able to handle it correctly.

It seems like it's possible that this is not the case, or at least for Webpack <= 3 when using Uglify, which requires setting the ecma: 6 option in order for it to not choke on the ES modules. I'm not sure what the right call is here - it seems like the "technically correct" way would be to leave it, and leave it to the end user to correctly configure (or upgrade) their build tools, but that also seems like it's not ideal, especially given the number of issues reported. An alternative could be to use the es2015 property instead of module, which is another proposal mainly used by Angular - but it'd allow people to opt in to using the ES modules, since it'd require explicitly adding es2015 to the resolve.mainFields property.

@DanielSchaffer
Copy link
Contributor

DanielSchaffer commented May 29, 2018

Minimal repro and fixes for webpack 3 and 4: https://github.com/DanielSchaffer/oidc-client-webpack

@DanielSchaffer
Copy link
Contributor

^^ updated to add fixes and a README

@DarkCow
Copy link

DarkCow commented May 29, 2018

@brockallen it appears you are doing it correctly? JS devops are so confusing and change a million miles an hour... It appears package.json main points to ~/lib/oidc-client.min.js, which is the output of your build path... Which goes Gulp->Webpack->babel... If you add env preset preset to babelrc, it should transpile completely to ecma5. But that is probably overkill

However, other people using webpack, should be transpiling their code for the browsers they are targeting. IMO you shouldn't be depending too heavily on 3rd party package maintainers to that... In webpack 3, you should be transpiling your code before minification. The nice thing about webpack 4, is that it uses the newest uglifyjs, thus making minification not require transpilation.

@donalfenwick
Copy link
Contributor

@DanielSchaffer Ahh, that makes sense now about how webpack is resolving the dependency via the module property in the package.json.
I have noticed that after upgrading to version 1.5 of the oidc-client in an angular 6 project the tests fail to run when targeting PhantomJS.
They fail with the error SyntaxError: Unexpected token 'const’ in karma_webpack/vendor.js and after inspecting this file it looks like webpack is pulling the ES6 code into the vendor bundle where it was pulling in lib/oidc-client.min.js prior to using v1.5.
If I change the module property in the oidc-client’s package.json to an es2015 property webpack seems to pick up the minified file again and everything works.

Ideally updating the webpack config to transpile the code when webpack is creating vendor.js would be the best solution, but in the case of angular cli they don’t directly expose webpack.config.js to the developer.
I guess the only way to get around it would be to ng eject the webpack config, but this isn’t always desirable.

@brockallen
Copy link
Member

brockallen commented Jun 3, 2018

So @DanielSchaffer, it was the addition of "module": "index.js", in project.json that is the culprit behind this. When I remove that from your repo, then it's working again. This simply means that importing this (for now) pulls in the transpiled version, and as is evident from this thread it was a breaking change. So for now I'm going to remove it to get people back up and running.

I'm happy to start a 2.0 version that changes how this is done, and make that the breaking change. How's that for a solution and a plan to move forward?

@brockallen
Copy link
Member

@PaulInglis and @larlew I pushed a "1.5.1-beta.1" with the change I mentioned above. Can you test it, please to see if you're back up and running?

@brockallen brockallen added this to the 1.5.1 milestone Jun 3, 2018
@DanielSchaffer
Copy link
Contributor

DanielSchaffer commented Jun 3, 2018

@brockallen can you change the module to es2015 rather than removing it entirely? After seeing these problems come in, I'm still not entirely clear on what's expected to be in module as far as ES level and module format, so I'm not sure that even doing a 2.0 to signify a breaking change is the right way to go. Using es2015 seems like it'll still make the things I was trying work with happy without breaking it for anyone else.

@PaulInglis
Copy link
Author

@brockallen - compiles fine for me (didn't before). Not done a thorough test yet (will do it tomorrow, when I have time), but I seemed to be able to hit the site with the cached token.

@brockallen
Copy link
Member

@DanielSchaffer wouldn't that also be a breaking change from what was in 1.4?

@DanielSchaffer
Copy link
Contributor

DanielSchaffer commented Jun 4, 2018

@brockallen I don't think so. The issue here is with how the various packaging tools resolve 3rd party libraries. I'm not familiar with how Rollup works, but for Webpack, it uses the resolve.mainFields property to determine which fields in the library's package.json file it uses to find the entry point for the library. By default resolve.mainFields is set to [ 'module', 'main' ]. If the target is set to 'web', then it defaults to [ 'browser', 'module', 'main' ]. That's why this change broke stuff for some people - if they weren't already set up to be transpiliing or using the latest Webpack, things choked on the ES2015 module because it was suddenly superceding the already transpiled file provided by main.

es2015 is not used by default - my understanding is that it's a proposal from Angular - and when it is used, it's expected that it provides ES2015 modules, so it should not be a breaking change for anyone.

@hawkeng
Copy link

hawkeng commented Jun 5, 2018

Users of create-react-app can't change the webpack version (not without ejecting) and thus the proposed solution of changing webpack's config/version is not suitable.

Please provide es5 version for build

@lyphtec
Copy link

lyphtec commented Jun 6, 2018

@hawkeng Lastest version (1.5.1-beta.1) works fine with create-react-app and you don't need to touch webpack. This is due to the removal of the module key in package.json - so it now uses the main key that points to lib/oidc-client.min.js which is already an ES5 version.

@brockallen
Copy link
Member

1.5.1 pushed

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

No branches or pull requests

9 participants