diff --git a/client-src/default/index.js b/client-src/default/index.js index 1d367ef495..f4fc40239d 100644 --- a/client-src/default/index.js +++ b/client-src/default/index.js @@ -6,7 +6,7 @@ window.process = window.process || {}; window.process.env = window.process.env || {}; /* global __resourceQuery WorkerGlobalScope self */ -const stripAnsi = require('strip-ansi'); +const stripAnsi = require('../transpiled-modules/strip-ansi'); const socket = require('./socket'); const overlay = require('./overlay'); const { log, setLogLevel } = require('./utils/log'); diff --git a/client-src/default/utils/log.js b/client-src/default/utils/log.js index 4063d8393a..78ee296c84 100644 --- a/client-src/default/utils/log.js +++ b/client-src/default/utils/log.js @@ -1,6 +1,6 @@ 'use strict'; -const log = require('webpack/lib/logging/runtime'); +const log = require('../../transpiled-modules/log'); const name = 'webpack-dev-server'; // default level is set on the client side, so it does not need diff --git a/client-src/transpiled-modules/log.js b/client-src/transpiled-modules/log.js new file mode 100644 index 0000000000..02c3765ae6 --- /dev/null +++ b/client-src/transpiled-modules/log.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('webpack/lib/logging/runtime'); diff --git a/client-src/transpiled-modules/strip-ansi.js b/client-src/transpiled-modules/strip-ansi.js new file mode 100644 index 0000000000..8f36ce2024 --- /dev/null +++ b/client-src/transpiled-modules/strip-ansi.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('strip-ansi'); diff --git a/client-src/transpiled-modules/webpack.config.js b/client-src/transpiled-modules/webpack.config.js new file mode 100644 index 0000000000..d1b38c1054 --- /dev/null +++ b/client-src/transpiled-modules/webpack.config.js @@ -0,0 +1,39 @@ +'use strict'; + +const path = require('path'); +const merge = require('webpack-merge'); + +const base = { + mode: 'production', + output: { + path: path.resolve(__dirname, '../../client/transpiled-modules'), + libraryTarget: 'commonjs2', + }, + module: { + rules: [ + { + test: /\.js$/, + use: [ + { + loader: 'babel-loader', + }, + ], + }, + ], + }, +}; + +module.exports = [ + merge(base, { + entry: path.join(__dirname, 'log.js'), + output: { + filename: 'log.js', + }, + }), + merge(base, { + entry: path.join(__dirname, 'strip-ansi.js'), + output: { + filename: 'strip-ansi.js', + }, + }), +]; diff --git a/package-lock.json b/package-lock.json index bb606fe715..8e7f83e4f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -133,11 +133,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } + "optional": true }, "glob-parent": { "version": "3.1.0", @@ -2813,9 +2809,9 @@ } }, "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.1.tgz", + "integrity": "sha512-dmKn4pqZ29iQl2Pvze1zTrps2luvls2PBY//neO2WJ0s10B3AxJXshN+Ph7B4GrhfGhHXrl4dnUwyNNXQcnWGQ==", "dev": true }, "acorn-globals": { @@ -2826,6 +2822,14 @@ "requires": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + } } }, "acorn-jsx": { @@ -3366,16 +3370,6 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, "bl": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", @@ -6622,6 +6616,14 @@ "acorn": "^7.3.1", "acorn-jsx": "^5.2.0", "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + } } }, "esprima": { @@ -7152,13 +7154,6 @@ } } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -10308,6 +10303,14 @@ "whatwg-url": "^8.0.0", "ws": "^7.2.3", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + } } }, "jsesc": { @@ -11388,13 +11391,6 @@ "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", - "dev": true, - "optional": true - }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -15469,11 +15465,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } + "optional": true }, "glob-parent": { "version": "3.1.0", @@ -16077,6 +16069,15 @@ "schema-utils": "^2.7.0" } }, + "webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, "webpack-sources": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", diff --git a/package.json b/package.json index 8c24480605..6faef2b868 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "build:client:clients": "babel client-src/clients --out-dir client/clients", "build:client:index": "webpack --color --config client-src/default/webpack.config.js", "build:client:sockjs": "webpack --color --config client-src/sockjs/webpack.config.js", + "build:client:transpiled-modules": "webpack --color --config client-src/transpiled-modules/webpack.config.js", "build:client": "rimraf ./client/* && npm-run-all -s -l -p \"build:client:**\"", "webpack-dev-server": "node examples/run-example.js", "release": "standard-version" @@ -74,6 +75,7 @@ "@commitlint/cli": "^9.1.2", "@commitlint/config-conventional": "^10.0.0", "@jest/test-sequencer": "^26.3.0", + "acorn": "^8.0.1", "babel-jest": "^26.3.0", "babel-loader": "^8.1.0", "body-parser": "^1.19.0", @@ -107,7 +109,8 @@ "typescript": "^3.9.7", "url-loader": "^4.1.0", "webpack": "^4.44.1", - "webpack-cli": "^3.3.12" + "webpack-cli": "^3.3.12", + "webpack-merge": "^4.2.2" }, "peerDependencies": { "webpack": "^4.0.0 || ^5.0.0" diff --git a/test/client/bundle.test.js b/test/client/bundle.test.js new file mode 100644 index 0000000000..8cdc3f378c --- /dev/null +++ b/test/client/bundle.test.js @@ -0,0 +1,79 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const acorn = require('acorn'); +const request = require('supertest'); +const testServer = require('../helpers/test-server'); +const config = require('../fixtures/simple-config/webpack.config'); +const port = require('../ports-map').bundle; +const isWebpack5 = require('../helpers/isWebpack5'); + +describe('bundle', () => { + // the ES5 check test for the bundle will not work on webpack@5, + // because webpack@5 bundle output uses some ES6 syntax that can + // only be avoided with babel-loader + const runBundleTest = isWebpack5 ? describe.skip : describe; + + runBundleTest('index.bundle.js bundled output', () => { + it('should parse with ES5', () => { + const bundleStr = fs.readFileSync( + path.resolve(__dirname, '../../client/default/index.bundle.js'), + 'utf8' + ); + expect(() => { + acorn.parse(bundleStr, { + ecmaVersion: 5, + }); + }).not.toThrow(); + }); + }); + + runBundleTest('main.js bundled output', () => { + let server; + let req; + + beforeAll((done) => { + server = testServer.start(config, { port }, done); + req = request(server.app); + }); + + afterAll(testServer.close); + + it('should get full user bundle and parse with ES5', async () => { + const { text } = await req + .get('/main.js') + .expect('Content-Type', 'application/javascript; charset=utf-8') + .expect(200); + + expect(() => { + let evalStep = 0; + acorn.parse(text, { + ecmaVersion: 5, + onToken: (token) => { + // a webpack bundle is a series of evaluated JavaScript + // strings like this: eval('...') + // if we want the bundle to work using ES5, we need to + // check that these strings are good with ES5 as well + + // this can be done by waiting for tokens during the main parse + // then when we hit a string in an 'eval' function we also try + // to parse that string with ES5 + if (token.type.label === 'name' && token.value === 'eval') { + evalStep += 1; + } else if (token.type.label === '(' && evalStep === 1) { + evalStep += 1; + } else if (token.type.label === 'string' && evalStep === 2) { + const program = token.value; + acorn.parse(program, { + ecmaVersion: 5, + }); + + evalStep = 0; + } + }, + }); + }).not.toThrow(); + }); + }); +}); diff --git a/test/ports-map.js b/test/ports-map.js index dca745ec24..46be5ef5e8 100644 --- a/test/ports-map.js +++ b/test/ports-map.js @@ -42,6 +42,8 @@ const portsList = { Iframe: 1, SocketInjection: 1, 'static-publicPath-option': 1, + 'contentBasePublicPath-option': 1, + bundle: 1, }; let startPort = 8089;