diff --git a/package.json b/package.json index 73cb97e5b5..8a0501fc94 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@types/react-dom": "^17.0.0", "@types/resize-observer-browser": "^0.1.4", "@types/rimraf": "^3.0.0", + "@types/webpack": "^4.41.25", "@types/ws": "7.2.6", "@typescript-eslint/eslint-plugin": "^3.10.1", "@typescript-eslint/parser": "^3.10.1", diff --git a/src/cli/injected/recorder.webpack.config.js b/src/cli/injected/recorder.webpack.config.js index 237bbfaaa3..13f840931f 100644 --- a/src/cli/injected/recorder.webpack.config.js +++ b/src/cli/injected/recorder.webpack.config.js @@ -17,10 +17,11 @@ const path = require('path'); const InlineSource = require('../../server/injected/webpack-inline-source-plugin'); +/** @type {import('webpack').Configuration} */ module.exports = { entry: path.join(__dirname, 'recorder.ts'), - devtool: 'source-map', - mode: 'development', + mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', + devtool: false, module: { rules: [ { @@ -38,6 +39,8 @@ module.exports = { }, output: { libraryTarget: 'var', + libraryExport: 'default', + library: 'pwExport', filename: 'recorderSource.js', path: path.resolve(__dirname, '../../../lib/server/injected/packed') }, diff --git a/src/debug/injected/consoleApi.webpack.config.js b/src/debug/injected/consoleApi.webpack.config.js index 68425ec480..9595fa0111 100644 --- a/src/debug/injected/consoleApi.webpack.config.js +++ b/src/debug/injected/consoleApi.webpack.config.js @@ -17,10 +17,11 @@ const path = require('path'); const InlineSource = require('../../server/injected/webpack-inline-source-plugin'); +/** @type {import('webpack').Configuration} */ module.exports = { entry: path.join(__dirname, 'consoleApi.ts'), - devtool: 'source-map', - mode: 'development', + mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', + devtool: false, module: { rules: [ { @@ -38,6 +39,8 @@ module.exports = { }, output: { libraryTarget: 'var', + library: 'pwExport', + libraryExport: 'default', filename: 'consoleApiSource.js', path: path.resolve(__dirname, '../../../lib/server/injected/packed') }, diff --git a/src/server/dom.ts b/src/server/dom.ts index 83b58d99a7..ada660e059 100644 --- a/src/server/dom.ts +++ b/src/server/dom.ts @@ -82,9 +82,12 @@ export class FrameExecutionContext extends js.ExecutionContext { for (const [name, { source }] of this.frame._page.selectors._engines) custom.push(`{ name: '${name}', engine: (${source}) }`); const source = ` - new (${injectedScriptSource.source})([ + (() => { + ${injectedScriptSource.source} + return new pwExport([ ${custom.join(',\n')} - ]) + ]); + })(); `; this._injectedScriptPromise = this._delegate.rawEvaluate(source).then(objectId => new js.JSHandle(this, 'object', objectId)); } diff --git a/src/server/injected/injectedScript.ts b/src/server/injected/injectedScript.ts index aeac733c96..ee8c173ab1 100644 --- a/src/server/injected/injectedScript.ts +++ b/src/server/injected/injectedScript.ts @@ -146,7 +146,11 @@ export class InjectedScript { } extend(source: string, params: any): any { - const constrFunction = global.eval(source); + const constrFunction = global.eval(` + (() => { + ${source} + return pwExport; + })()`); return new constrFunction(this, params); } diff --git a/src/server/injected/injectedScript.webpack.config.js b/src/server/injected/injectedScript.webpack.config.js index dc4a08a986..16ecd22a54 100644 --- a/src/server/injected/injectedScript.webpack.config.js +++ b/src/server/injected/injectedScript.webpack.config.js @@ -16,11 +16,11 @@ const path = require('path'); const InlineSource = require('./webpack-inline-source-plugin.js'); - +/** @type {import('webpack').Configuration} */ module.exports = { entry: path.join(__dirname, 'injectedScript.ts'), - devtool: 'source-map', - mode: 'development', + mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', + devtool: false, module: { rules: [ { @@ -38,6 +38,9 @@ module.exports = { }, output: { filename: 'injectedScriptSource.js', + libraryTarget: 'var', + libraryExport: 'default', + library: 'pwExport', path: path.resolve(__dirname, '../../../lib/server/injected/packed') }, plugins: [ diff --git a/src/server/injected/utilityScript.webpack.config.js b/src/server/injected/utilityScript.webpack.config.js index c58f303071..5102617e50 100644 --- a/src/server/injected/utilityScript.webpack.config.js +++ b/src/server/injected/utilityScript.webpack.config.js @@ -17,10 +17,11 @@ const path = require('path'); const InlineSource = require('./webpack-inline-source-plugin.js'); +/** @type {import('webpack').Configuration} */ module.exports = { entry: path.join(__dirname, 'utilityScript.ts'), - devtool: 'source-map', - mode: 'development', + mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', + devtool: false, module: { rules: [ { @@ -38,6 +39,8 @@ module.exports = { }, output: { libraryTarget: 'var', + library: 'pwExport', + libraryExport: 'default', filename: 'utilityScriptSource.js', path: path.resolve(__dirname, '../../../lib/server/injected/packed') }, diff --git a/src/server/injected/webpack-inline-source-plugin.js b/src/server/injected/webpack-inline-source-plugin.js index d587d732a8..cca3b4d310 100644 --- a/src/server/injected/webpack-inline-source-plugin.js +++ b/src/server/injected/webpack-inline-source-plugin.js @@ -22,15 +22,12 @@ module.exports = class InlineSource { this.outFile = outFile; } + /** + * @param {import('webpack').Compiler} compiler + */ apply(compiler) { compiler.hooks.emit.tapAsync('InlineSource', (compilation, callback) => { - let source = compilation.assets[path.basename(this.outFile).replace('.ts', '.js')].source(); - const lastLine = source.split('\n').pop(); - if (lastLine.startsWith('//# sourceMappingURL')) - source = source.substring(0, source.length - lastLine.length - 1); - if (source.endsWith(';')) - source = source.substring(0, source.length - 1); - source = '(' + source + ').default'; + const source = compilation.assets[path.basename(this.outFile).replace('.ts', '.js')].source(); fs.mkdirSync(path.dirname(this.outFile), { recursive: true }); const newSource = 'export const source = ' + JSON.stringify(source) + ';'; fs.writeFileSync(this.outFile, newSource); diff --git a/src/server/javascript.ts b/src/server/javascript.ts index e3e92bb02e..298c086a78 100644 --- a/src/server/javascript.ts +++ b/src/server/javascript.ts @@ -64,7 +64,11 @@ export class ExecutionContext { utilityScript(): Promise> { if (!this._utilityScriptPromise) { - const source = `new (${utilityScriptSource.source})()`; + const source = ` + (() => { + ${utilityScriptSource.source} + return new pwExport(); + })();`; this._utilityScriptPromise = this._delegate.rawEvaluate(source).then(objectId => new JSHandle(this, 'object', objectId)); } return this._utilityScriptPromise; diff --git a/test/page-evaluate.spec.ts b/test/page-evaluate.spec.ts index b28c1c5ff9..e53e31cc52 100644 --- a/test/page-evaluate.spec.ts +++ b/test/page-evaluate.spec.ts @@ -554,3 +554,7 @@ it('should not use toJSON in jsonValue', async ({ page }) => { const resultHandle = await page.evaluateHandle(() => ({ toJSON: () => 'string', data: 'data' })); expect(await resultHandle.jsonValue()).toEqual({ data: 'data', toJSON: {} }); }); + +it('should not expose the injected script export', async ({ page }) => { + expect(await page.evaluate('typeof pwExport === "undefined"')).toBe(true); +}); diff --git a/utils/build/build.js b/utils/build/build.js index 00902353ab..693bf98966 100644 --- a/utils/build/build.js +++ b/utils/build/build.js @@ -40,7 +40,10 @@ function runWatch() { const spawns = []; for (const step of steps) - spawns.push(child_process.spawn(step.command, step.args, { stdio: 'inherit', shell: step.shell })); + spawns.push(child_process.spawn(step.command, step.args, { stdio: 'inherit', shell: step.shell, env: { + ...process.env, + ...step.env, + } })); process.on('exit', () => spawns.forEach(s => s.kill())); for (const onChange of onChanges) runOnChanges(onChange.inputs, onChange.script); @@ -72,8 +75,11 @@ const webPackFiles = [ for (const file of webPackFiles) { steps.push({ command: 'npx', - args: ['webpack', '--config', filePath(file), ...(watchMode ? ['--watch', '--silent', '--mode', 'development'] : [])], + args: ['webpack', '--config', filePath(file), ...(watchMode ? ['--watch', '--silent'] : [])], shell: true, + env: { + NODE_ENV: watchMode ? 'development' : 'production' + } }); }