From 1a0f86a18c22a9ab518eacd5061c7f6a5c5860ee Mon Sep 17 00:00:00 2001 From: James Bourne Date: Thu, 7 May 2020 13:31:55 +0100 Subject: [PATCH 01/32] Skip compile & packaging if --no-build is set (#560) * Add copyExistingArtifacts to packageModules * Refactor packageModules * Set service path * Generate artifact name from service * Output artifacts to .webpack before copying * Set artifact name for service packaging * Skip webpack:compile if --no-build is set * Add webpack:package:copyExistingArtifacts hook * Make packageModules & packExternalModules no-op if skipCompile is set * Refactor packageModules * Remove artifact location setting from packageModules * Update cleanup to check this.keepOutputDirectory * Fix path join on Windows Co-authored-by: Miguel A. Calles MBA <44813512+miguel-a-calles-mba@users.noreply.github.com> --- index.js | 10 +- index.test.js | 29 +++- lib/cleanup.js | 2 +- lib/packExternalModules.js | 4 + lib/packageModules.js | 116 ++++++++++---- lib/validate.js | 4 +- tests/cleanup.test.js | 5 +- tests/mocks/fs.mock.js | 1 + tests/packExternalModules.test.js | 18 +++ tests/packageModules.test.js | 245 ++++++++++++++++++++++++++++-- tests/validate.test.js | 22 ++- 11 files changed, 400 insertions(+), 56 deletions(-) diff --git a/index.js b/index.js index 326669c47..e370bbebf 100644 --- a/index.js +++ b/index.js @@ -81,7 +81,7 @@ class ServerlessWebpack { }, package: { type: 'entrypoint', - lifecycleEvents: [ 'packExternalModules', 'packageModules' ] + lifecycleEvents: [ 'packExternalModules', 'packageModules', 'copyExistingArtifacts' ] } } } @@ -91,7 +91,7 @@ class ServerlessWebpack { 'before:package:createDeploymentArtifacts': () => BbPromise.bind(this) .then(() => this.serverless.pluginManager.spawn('webpack:validate')) - .then(() => this.serverless.pluginManager.spawn('webpack:compile')) + .then(() => (this.skipCompile ? BbPromise.resolve() : this.serverless.pluginManager.spawn('webpack:compile'))) .then(() => this.serverless.pluginManager.spawn('webpack:package')), 'after:package:createDeploymentArtifacts': () => BbPromise.bind(this).then(this.cleanup), @@ -106,10 +106,6 @@ class ServerlessWebpack { BbPromise.bind(this) .then(() => { lib.webpack.isLocal = true; - // --no-build override - if (this.options.build === false) { - this.skipCompile = true; - } return this.serverless.pluginManager.spawn('webpack:validate'); }) @@ -159,6 +155,8 @@ class ServerlessWebpack { 'webpack:package:packageModules': () => BbPromise.bind(this).then(this.packageModules), + 'webpack:package:copyExistingArtifacts': () => BbPromise.bind(this).then(this.copyExistingArtifacts), + 'before:offline:start': () => BbPromise.bind(this) .tap(() => { diff --git a/index.test.js b/index.test.js index ab0a03bcc..585e8b70a 100644 --- a/index.test.js +++ b/index.test.js @@ -133,6 +133,7 @@ describe('ServerlessWebpack', () => { sandbox.stub(slsw, 'watch').returns(BbPromise.resolve()); sandbox.stub(slsw, 'wpwatch').returns(BbPromise.resolve()); sandbox.stub(slsw, 'packExternalModules').returns(BbPromise.resolve()); + sandbox.stub(slsw, 'copyExistingArtifacts').returns(BbPromise.resolve()); sandbox.stub(slsw, 'prepareRun').returns(BbPromise.resolve()); sandbox.stub(slsw, 'watchRun').returns(BbPromise.resolve()); sandbox.stub(slsw, 'validate').returns(BbPromise.resolve()); @@ -145,6 +146,7 @@ describe('ServerlessWebpack', () => { beforeEach(() => { ServerlessWebpack.lib.webpack.isLocal = false; + slsw.skipCompile = false; }); after(() => { @@ -169,6 +171,20 @@ describe('ServerlessWebpack', () => { return null; }); }); + + it('should skip compile if requested', () => { + slsw.skipCompile = true; + return expect(slsw.hooks['before:package:createDeploymentArtifacts']()).to.be.fulfilled.then(() => { + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledTwice; + expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly( + 'webpack:validate' + ); + expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly( + 'webpack:package' + ); + return null; + }); + }); } }, { @@ -237,7 +253,7 @@ describe('ServerlessWebpack', () => { }); it('should skip compile if requested', () => { - slsw.options.build = false; + slsw.skipCompile = true; return expect(slsw.hooks['before:invoke:local:invoke']()).to.be.fulfilled.then(() => { expect(slsw.serverless.pluginManager.spawn).to.have.been.calledOnce; expect(slsw.serverless.pluginManager.spawn).to.have.been.calledWithExactly('webpack:validate'); @@ -361,6 +377,17 @@ describe('ServerlessWebpack', () => { }); } }, + { + name: 'webpack:package:copyExistingArtifacts', + test: () => { + it('should call copyExistingArtifacts', () => { + return expect(slsw.hooks['webpack:package:copyExistingArtifacts']()).to.be.fulfilled.then(() => { + expect(slsw.copyExistingArtifacts).to.have.been.calledOnce; + return null; + }); + }); + } + }, { name: 'before:offline:start', test: () => { diff --git a/lib/cleanup.js b/lib/cleanup.js index 63bfcc796..9173529ff 100644 --- a/lib/cleanup.js +++ b/lib/cleanup.js @@ -7,7 +7,7 @@ module.exports = { cleanup() { const webpackOutputPath = this.webpackOutputPath; - const keepOutputDirectory = this.configuration.keepOutputDirectory; + const keepOutputDirectory = this.keepOutputDirectory; if (!keepOutputDirectory) { this.options.verbose && this.serverless.cli.log(`Remove ${webpackOutputPath}`); if (this.serverless.utils.dirExistsSync(webpackOutputPath)) { diff --git a/lib/packExternalModules.js b/lib/packExternalModules.js index cd762a304..8ae24e6c1 100644 --- a/lib/packExternalModules.js +++ b/lib/packExternalModules.js @@ -228,6 +228,10 @@ module.exports = { * and performance. */ packExternalModules() { + if (this.skipCompile) { + return BbPromise.resolve(); + } + const stats = this.compileStats; const includes = this.configuration.includeModules; diff --git a/lib/packageModules.js b/lib/packageModules.js index 422af3893..5026f2c29 100644 --- a/lib/packageModules.js +++ b/lib/packageModules.js @@ -11,6 +11,8 @@ const semver = require('semver'); function setArtifactPath(funcName, func, artifactPath) { const version = this.serverless.getVersion(); + this.options.verbose && this.serverless.cli.log(`Setting artifact for function '${funcName}' to '${artifactPath}'`); + // Serverless changed the artifact path location in version 1.18 if (semver.lt(version, '1.18.0')) { func.artifact = artifactPath; @@ -26,7 +28,8 @@ function setArtifactPath(funcName, func, artifactPath) { function zip(directory, name) { const zip = archiver.create('zip'); // Create artifact in temp path and move it to the package path (if any) later - const artifactFilePath = path.join(this.serverless.config.servicePath, '.serverless', name); + // This allows us to persist the webpackOutputPath and re-use the compiled output + const artifactFilePath = path.join(this.webpackOutputPath, name); this.serverless.utils.writeFileDir(artifactFilePath); const output = fs.createWriteStream(artifactFilePath); @@ -69,13 +72,47 @@ function zip(directory, name) { }); } +function getArtifactLocations(name) { + const archiveName = `${name}.zip`; + + const webpackArtifact = path.join(this.webpackOutputPath, archiveName); + const serverlessArtifact = path.join('.serverless', archiveName); + + return { webpackArtifact, serverlessArtifact }; +} + +function copyArtifactByName(artifactName) { + const { webpackArtifact, serverlessArtifact } = getArtifactLocations.call(this, artifactName); + + // Make sure the destination dir exists + this.serverless.utils.writeFileDir(serverlessArtifact); + + fs.copyFileSync(webpackArtifact, serverlessArtifact); +} + +function setServiceArtifactPath(artifactPath) { + _.set(this.serverless, 'service.package.artifact', artifactPath); +} + +function isIndividialPackaging() { + return _.get(this.serverless, 'service.package.individually'); +} + +function getArtifactName(entryFunction) { + return `${entryFunction.funcName || this.serverless.service.getServiceObject().name}.zip`; +} + module.exports = { packageModules() { + if (this.skipCompile) { + return BbPromise.resolve(); + } + const stats = this.compileStats; return BbPromise.mapSeries(stats.stats, (compileStats, index) => { const entryFunction = _.get(this.entryFunctions, index, {}); - const filename = `${entryFunction.funcName || this.serverless.service.getServiceObject().name}.zip`; + const filename = getArtifactName.call(this, entryFunction); const modulePath = compileStats.compilation.compiler.outputPath; const startZip = _.now(); @@ -87,37 +124,52 @@ module.exports = { this.serverless.cli.log( `Zip ${_.isEmpty(entryFunction) ? 'service' : 'function'}: ${modulePath} [${_.now() - startZip} ms]` ) - ) - .then(artifactPath => { - if (_.get(this.serverless, 'service.package.individually')) { - setArtifactPath.call( - this, - entryFunction.funcName, - entryFunction.func, - path.relative(this.serverless.config.servicePath, artifactPath) - ); - } - return artifactPath; - }); - }).then(artifacts => { - if (!_.get(this.serverless, 'service.package.individually') && !_.isEmpty(artifacts)) { - // Set the service artifact to all functions - const allFunctionNames = this.serverless.service.getAllFunctions(); - _.forEach(allFunctionNames, funcName => { - const func = this.serverless.service.getFunction(funcName); - setArtifactPath.call(this, funcName, func, path.relative(this.serverless.config.servicePath, artifacts[0])); - }); - // For Google set the service artifact path - if (_.get(this.serverless, 'service.provider.name') === 'google') { - _.set( - this.serverless, - 'service.package.artifact', - path.relative(this.serverless.config.servicePath, artifacts[0]) - ); - } - } + ); + }); + }, + + copyExistingArtifacts() { + this.serverless.cli.log('Copying existing artifacts...'); + const allFunctionNames = this.serverless.service.getAllFunctions(); + + // Copy artifacts to package location + if (isIndividialPackaging.call(this)) { + _.forEach(allFunctionNames, funcName => copyArtifactByName.call(this, funcName)); + } else { + // Copy service packaged artifact + const serviceName = this.serverless.service.getServiceObject().name; + copyArtifactByName.call(this, serviceName); + } + + _.forEach(allFunctionNames, funcName => { + const func = this.serverless.service.getFunction(funcName); + + const archiveName = isIndividialPackaging.call(this) ? funcName : this.serverless.service.getServiceObject().name; - return null; + const { serverlessArtifact } = getArtifactLocations.call(this, archiveName); + setArtifactPath.call(this, funcName, func, serverlessArtifact); }); + + // Set artifact locations + if (isIndividialPackaging.call(this)) { + _.forEach(allFunctionNames, funcName => { + const func = this.serverless.service.getFunction(funcName); + + const archiveName = funcName; + + const { serverlessArtifact } = getArtifactLocations.call(this, archiveName); + setArtifactPath.call(this, funcName, func, serverlessArtifact); + }); + } else { + const archiveName = this.serverless.service.getServiceObject().name; + + const { serverlessArtifact } = getArtifactLocations.call(this, archiveName); + + if (_.get(this.serverless, 'service.provider.name') === 'google') { + setServiceArtifactPath.call(this, serverlessArtifact); + } + } + + return BbPromise.resolve(); } }; diff --git a/lib/validate.js b/lib/validate.js index 80c0eb784..b46d8532d 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -171,7 +171,9 @@ module.exports = { this.webpackConfig.output.path = path.join(this.serverless.config.servicePath, this.options.out); } - if (this.skipCompile) { + // Skip compilation with --no-build + if (this.options.build === false) { + this.skipCompile = true; this.serverless.cli.log('Skipping build and using existing compiled output'); if (!fse.pathExistsSync(this.webpackConfig.output.path)) { return BbPromise.reject(new this.serverless.classes.Error('No compiled output found')); diff --git a/tests/cleanup.test.js b/tests/cleanup.test.js index 4d9eda2d2..2be4cd3a2 100644 --- a/tests/cleanup.test.js +++ b/tests/cleanup.test.js @@ -55,8 +55,7 @@ describe('cleanup', () => { { serverless, options: {}, - webpackOutputPath: 'my/Output/Path', - configuration: {} + webpackOutputPath: 'my/Output/Path' }, baseModule ); @@ -96,7 +95,7 @@ describe('cleanup', () => { fseMock.removeSync.reset(); const configuredModule = _.assign({}, module, { - configuration: { keepOutputDirectory: true } + keepOutputDirectory: true }); return expect(configuredModule.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.not.have.been.calledOnce; diff --git a/tests/mocks/fs.mock.js b/tests/mocks/fs.mock.js index 8590528a3..a9e06cea8 100644 --- a/tests/mocks/fs.mock.js +++ b/tests/mocks/fs.mock.js @@ -23,6 +23,7 @@ module.exports.create = sandbox => { readFileSync: sandbox.stub(), statSync: sinon.stub().returns(statMock), // Persistent stub writeFileSync: sandbox.stub(), + copyFileSync: sandbox.stub(), _streamMock: streamMock, _statMock: statMock diff --git a/tests/packExternalModules.test.js b/tests/packExternalModules.test.js index b1abd4305..236ea593b 100644 --- a/tests/packExternalModules.test.js +++ b/tests/packExternalModules.test.js @@ -334,6 +334,24 @@ describe('packExternalModules', () => { ); }); + it('should do nothing if skipCompile is true', () => { + module.configuration = new Configuration({ + webpack: { + includeModules: { + packagePath: path.join('locals', 'package.json') + } + } + }); + module.skipCompile = true; + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(fsExtraMock.copy).to.not.have.been.called, + expect(packagerFactoryMock.get).to.not.have.been.called, + expect(writeFileSyncStub).to.not.have.been.called + ]) + ); + }); + it('should copy needed package sections if available', () => { const originalPackageJSON = { name: 'test-service', diff --git a/tests/packageModules.test.js b/tests/packageModules.test.js index 0d5665bea..92c15fc8b 100644 --- a/tests/packageModules.test.js +++ b/tests/packageModules.test.js @@ -72,7 +72,8 @@ describe('packageModules', () => { module = _.assign( { serverless, - options: {} + options: {}, + webpackOutputPath: '.webpack' }, baseModule ); @@ -97,6 +98,18 @@ describe('packageModules', () => { ); }); + it('should do nothing if skipCompile is true', () => { + module.skipCompile = true; + return expect(module.packageModules()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(archiverMock.create).to.not.have.been.called, + expect(writeFileDirStub).to.not.have.been.called, + expect(fsMock.createWriteStream).to.not.have.been.called, + expect(globMock.sync).to.not.have.been.called + ]) + ); + }); + describe('with service packaging', () => { beforeEach(() => { // Setup behavior for service packaging @@ -142,8 +155,6 @@ describe('packageModules', () => { fsMock._streamMock.on.withArgs('close').yields(); fsMock._statMock.isDirectory.returns(false); - const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); - module.compileStats = stats; return expect(module.packageModules()).to.be.fulfilled.then(() => BbPromise.all([ @@ -207,8 +218,6 @@ describe('packageModules', () => { fsMock._streamMock.on.withArgs('close').yields(); fsMock._statMock.isDirectory.returns(false); - const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); - module.compileStats = stats; return expect(module.packageModules()).to.be.fulfilled.then(() => expect(serverless.service).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath) @@ -253,8 +262,6 @@ describe('packageModules', () => { fsMock._streamMock.on.withArgs('close').yields(); fsMock._statMock.isDirectory.returns(false); - const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); - module.compileStats = stats; return BbPromise.each([ '1.18.1', '2.17.0', '10.15.3' ], version => { getVersionStub.returns(version); @@ -388,14 +395,232 @@ describe('packageModules', () => { fsMock._statMock.isDirectory.returns(false); module.compileStats = stats; - return expect(module.packageModules()).to.be.fulfilled.then(() => + + return expect(module.packageModules()).to.be.fulfilled; + }); + }); + }); + + describe('copyExistingArtifacts()', () => { + const allFunctions = [ 'func1', 'func2' ]; + const func1 = { + handler: 'src/handler1', + events: [] + }; + const func2 = { + handler: 'src/handler2', + events: [] + }; + + const entryFunctions = [ + { + handlerFile: 'src/handler1.js', + funcName: 'func1', + func: func1 + }, + { + handlerFile: 'src/handler2.js', + funcName: 'func2', + func: func2 + } + ]; + + describe('with service packaging', () => { + afterEach(() => { + fsMock.copyFileSync.resetHistory(); + }); + + beforeEach(() => { + _.set(module, 'entryFunctions', entryFunctions); + _.set(serverless.service.package, 'individually', false); + getVersionStub.returns('1.18.0'); + getServiceObjectStub.returns({ + name: 'test-service' + }); + getAllFunctionsStub.returns(allFunctions); + getFunctionStub.withArgs('func1').returns(func1); + getFunctionStub.withArgs('func2').returns(func2); + }); + + it('copies the artifact', () => { + const expectedArtifactSource = path.join('.webpack', 'test-service.zip'); + const expectedArtifactDestination = path.join('.serverless', 'test-service.zip'); + + return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => + BbPromise.all([ + // Should copy the artifact into .serverless + expect(fsMock.copyFileSync).callCount(1), + expect(fsMock.copyFileSync).to.be.calledWith(expectedArtifactSource, expectedArtifactDestination), + + // Should set package artifact for each function to the single artifact + expect(func1) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactDestination), + expect(func2) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactDestination) + ]) + ); + }); + + it('should set the function artifact depending on the serverless version', () => { + // Test data + const stats = { + stats: [ + { + compilation: { + compiler: { + outputPath: '/my/Service/Path/.webpack/service' + } + } + } + ] + }; + const files = [ 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' ]; + const allFunctions = [ 'func1', 'func2' ]; + const func1 = { + handler: 'src/handler1', + events: [] + }; + const func2 = { + handler: 'src/handler2', + events: [] + }; + // Serverless behavior + sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path'); + getServiceObjectStub.returns({ + name: 'test-service' + }); + getAllFunctionsStub.returns(allFunctions); + getFunctionStub.withArgs('func1').returns(func1); + getFunctionStub.withArgs('func2').returns(func2); + // Mock behavior + globMock.sync.returns(files); + fsMock._streamMock.on.withArgs('open').yields(); + fsMock._streamMock.on.withArgs('close').yields(); + fsMock._statMock.isDirectory.returns(false); + + const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); + + module.compileStats = stats; + return BbPromise.each([ '1.18.1', '2.17.0', '10.15.3' ], version => { + getVersionStub.returns(version); + return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(func1) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactPath), + expect(func2) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactPath) + ]) + ); + }).then(() => + BbPromise.each([ '1.17.0', '1.16.0-alpha', '1.15.3' ], version => { + getVersionStub.returns(version); + return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(func1) + .to.have.a.nested.property('artifact') + .that.equals(expectedArtifactPath), + expect(func2) + .to.have.a.nested.property('artifact') + .that.equals(expectedArtifactPath), + expect(func1).to.have.a.nested.property('package.disable').that.is.true, + expect(func2).to.have.a.nested.property('package.disable').that.is.true + ]) + ); + }) + ); + }); + + describe('with the Google provider', () => { + let oldProviderName; + + beforeEach(() => { + oldProviderName = serverless.service.provider.name; + // Imitate Google provider + serverless.service.provider.name = 'google'; + }); + + afterEach(() => { + if (oldProviderName) { + serverless.service.provider.name = oldProviderName; + } else { + _.unset(serverless.service.provider, 'name'); + } + }); + + it('should set the service artifact path', () => { + // Test data + const allFunctions = [ 'func1', 'func2' ]; + const func1 = { + handler: 'handler1', + events: [] + }; + const func2 = { + handler: 'handler2', + events: [] + }; + sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path'); + getVersionStub.returns('1.18.0'); + getServiceObjectStub.returns({ + name: 'test-service' + }); + getAllFunctionsStub.returns(allFunctions); + getFunctionStub.withArgs('func1').returns(func1); + getFunctionStub.withArgs('func2').returns(func2); + // Mock behavior + // fsMock._streamMock.on.withArgs('open').yields(); + // fsMock._streamMock.on.withArgs('close').yields(); + // fsMock._statMock.isDirectory.returns(false); + + const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); + + return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => + expect(serverless.service) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactPath) + ); + }); + }); + }); + + describe('with individual packaging', () => { + afterEach(() => { + fsMock.copyFileSync.resetHistory(); + }); + + beforeEach(() => { + _.set(module, 'entryFunctions', entryFunctions); + _.set(serverless.service.package, 'individually', true); + getVersionStub.returns('1.18.0'); + getServiceObjectStub.returns({ + name: 'test-service' + }); + getAllFunctionsStub.returns(allFunctions); + getFunctionStub.withArgs('func1').returns(func1); + getFunctionStub.withArgs('func2').returns(func2); + }); + + it('copies each artifact', () => { + const expectedFunc1Destination = path.join('.serverless', 'func1.zip'); + const expectedFunc2Destination = path.join('.serverless', 'func2.zip'); + + return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => BbPromise.all([ + // Should copy an artifact per function into .serverless + expect(fsMock.copyFileSync).callCount(2), + expect(fsMock.copyFileSync).to.be.calledWith(path.join('.webpack', 'func1.zip'), expectedFunc1Destination), + expect(fsMock.copyFileSync).to.be.calledWith(path.join('.webpack', 'func2.zip'), expectedFunc2Destination), + + // Should set package artifact locations expect(func1) .to.have.a.nested.property('package.artifact') - .that.equals(path.join('.serverless', 'func1.zip')), + .that.equals(expectedFunc1Destination), expect(func2) .to.have.a.nested.property('package.artifact') - .that.equals(path.join('.serverless', 'func2.zip')) + .that.equals(expectedFunc2Destination) ]) ); }); diff --git a/tests/validate.test.js b/tests/validate.test.js index 12c2ae89a..24c513aa9 100644 --- a/tests/validate.test.js +++ b/tests/validate.test.js @@ -960,6 +960,24 @@ describe('validate', () => { }); describe('with skipped builds', () => { + it('should set `skipComile` to true if `options.build` is false', () => { + const testConfig = { + entry: 'test', + output: {} + }; + const testServicePath = 'testpath'; + module.serverless.config.servicePath = testServicePath; + _.set(module.serverless.service, 'custom.webpack.config', testConfig); + + module.options.build = false; + + fsExtraMock.pathExistsSync.returns(true); + return module.validate().then(() => { + expect(module.skipCompile).to.be.true; + return null; + }); + }); + it('should keep output directory', () => { const testConfig = { entry: 'test', @@ -968,7 +986,7 @@ describe('validate', () => { const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - module.skipCompile = true; + module.options.build = false; fsExtraMock.pathExistsSync.returns(true); return module.validate().then(() => { expect(module.keepOutputDirectory).to.be.true; @@ -984,7 +1002,7 @@ describe('validate', () => { const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - module.skipCompile = true; + module.options.build = false; fsExtraMock.pathExistsSync.returns(false); return expect(module.validate()).to.be.rejectedWith(/No compiled output found/); }); From b44716b3941139831ceed91d5f9cc8d20bb3f0ea Mon Sep 17 00:00:00 2001 From: Andrew Sprouse Date: Fri, 14 Jun 2019 01:21:23 -0400 Subject: [PATCH 02/32] Serialized compile to address #299 --- lib/Configuration.js | 7 ++- lib/Configuration.test.js | 12 ++++-- lib/compile.js | 79 ++++++++++++++++++++-------------- lib/validate.js | 3 +- tests/compile.test.js | 90 +++++++++++++++++++++++++-------------- tests/webpack.mock.js | 12 ++++-- 6 files changed, 129 insertions(+), 74 deletions(-) diff --git a/lib/Configuration.js b/lib/Configuration.js index a3fde813e..2022ca913 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -14,7 +14,8 @@ const DefaultConfig = { packager: 'npm', packagerOptions: {}, keepOutputDirectory: false, - config: null + config: null, + serializedCompile: false }; class Configuration { @@ -73,6 +74,10 @@ class Configuration { return this._config.keepOutputDirectory; } + get serializedCompile() { + return this._config.serializedCompile; + } + toJSON() { return _.omitBy(this._config, _.isNil); } diff --git a/lib/Configuration.test.js b/lib/Configuration.test.js index b978eff8a..4324b4bde 100644 --- a/lib/Configuration.test.js +++ b/lib/Configuration.test.js @@ -19,7 +19,8 @@ describe('Configuration', () => { packager: 'npm', packagerOptions: {}, keepOutputDirectory: false, - config: null + config: null, + serializedCompile: false }; }); @@ -68,7 +69,8 @@ describe('Configuration', () => { packager: 'npm', packagerOptions: {}, keepOutputDirectory: false, - config: null + config: null, + serializedCompile: false }); }); }); @@ -88,7 +90,8 @@ describe('Configuration', () => { packager: 'npm', packagerOptions: {}, keepOutputDirectory: false, - config: null + config: null, + serializedCompile: false }); }); @@ -107,7 +110,8 @@ describe('Configuration', () => { packager: 'npm', packagerOptions: {}, keepOutputDirectory: false, - config: null + config: null, + serializedCompile: false }); }); }); diff --git a/lib/compile.js b/lib/compile.js index e5c2363cf..683242f7a 100644 --- a/lib/compile.js +++ b/lib/compile.js @@ -5,44 +5,57 @@ const BbPromise = require('bluebird'); const webpack = require('webpack'); const tty = require('tty'); -module.exports = { - compile() { - this.serverless.cli.log('Bundling with Webpack...'); +const defaultStatsConfig = { + colors: tty.isatty(process.stdout.fd), + hash: false, + version: false, + chunks: false, + children: false +}; - const compiler = webpack(this.webpackConfig); - - return BbPromise.fromCallback(cb => compiler.run(cb)).then(stats => { - if (!this.multiCompile) { - stats = { stats: [stats] }; - } - - const compileOutputPaths = []; - const consoleStats = this.webpackConfig.stats || - _.get(this, 'webpackConfig[0].stats') || { - colors: tty.isatty(process.stdout.fd), - hash: false, - version: false, - chunks: false, - children: false - }; - - _.forEach(stats.stats, compileStats => { - const statsOutput = compileStats.toString(consoleStats); - if (statsOutput) { - this.serverless.cli.consoleLog(statsOutput); +function ensureArray(obj) { + return _.isArray(obj) ? obj : [obj]; +} + +function getStatsLogger(statsConfig, consoleLog) { + return stats => consoleLog(stats.toString(statsConfig || defaultStatsConfig)); +} + +function webpackCompile(config, logStats) { + return BbPromise + .fromCallback(cb => webpack(config).run(cb)) + .then(stats => { + // ensure stats in any array in the case of multiCompile + stats = stats.stats ? stats.stats : [stats]; + + _.forEach(stats, compileStats => { + logStats(compileStats); + if (compileStats.hasErrors()) { + throw new Error('Webpack compilation error, see stats above'); } + }); - if (compileStats.compilation.errors.length) { - throw new Error('Webpack compilation error, see above'); - } + return stats; + }); +} - compileOutputPaths.push(compileStats.compilation.compiler.outputPath); - }); +function webpackCompileSerial(configs, logStats) { + return BbPromise + .mapSeries(configs, config => webpackCompile(config, logStats)) + .then(stats => _.flatten(stats)); +} - this.compileOutputPaths = compileOutputPaths; - this.compileStats = stats; +module.exports = { + compile() { + this.serverless.cli.log('Bundling with Webpack...'); - return BbPromise.resolve(); - }); + const configs = ensureArray(this.webpackConfig); + const logStats = getStatsLogger(configs[0].stats, this.serverless.cli.consoleLog); + + return (this.serializedCompile ? webpackCompileSerial : webpackCompile)(configs, logStats) + .then(stats => { + this.compileStats = { stats }; + return BbPromise.resolve(); + }); } }; diff --git a/lib/validate.js b/lib/validate.js index b46d8532d..80d8999cc 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -189,8 +189,9 @@ module.exports = { // In case of individual packaging we have to create a separate config for each function if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) { - this.options.verbose && this.serverless.cli.log('Using multi-compile (individual packaging)'); this.multiCompile = true; + this.serializedCompile = this.configuration.serializedCompile; + this.options.verbose && this.serverless.cli.log(`Using ${this.serializedCompile ? 'serialized' : 'multi'}-compile (individual packaging)`); if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) { return BbPromise.reject( diff --git a/tests/compile.test.js b/tests/compile.test.js index c0bcb672a..58f682029 100644 --- a/tests/compile.test.js +++ b/tests/compile.test.js @@ -44,13 +44,10 @@ describe('compile', () => { consoleLog: sandbox.stub() }; - module = _.assign( - { - serverless, - options: {} - }, - baseModule - ); + module = _.assign({ + serverless, + options: {}, + }, baseModule); }); afterEach(() => { @@ -65,8 +62,9 @@ describe('compile', () => { it('should compile with webpack from a context configuration', () => { const testWebpackConfig = 'testconfig'; module.webpackConfig = testWebpackConfig; - return expect(module.compile()).to.be.fulfilled.then(() => { - expect(webpackMock).to.have.been.calledWith(testWebpackConfig); + return expect(module.compile()).to.be.fulfilled + .then(() => { + expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); expect(webpackMock.compilerMock.run).to.have.been.calledOnce; return null; }); @@ -80,29 +78,58 @@ describe('compile', () => { }); it('should work with multi compile', () => { - const testWebpackConfig = 'testconfig'; - const multiStats = [ - { + const testWebpackConfig = ['testconfig']; + const multiStats = { + stats: [{ compilation: { errors: [], compiler: { - outputPath: 'statsMock-outputPath' - } + outputPath: 'statsMock-outputPath', + }, }, - toString: sandbox.stub().returns('testStats') - } - ]; + toString: sandbox.stub().returns('testStats'), + hasErrors: _.constant(false) + }] + }; module.webpackConfig = testWebpackConfig; module.multiCompile = true; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, multiStats); - return expect(module.compile()).to.be.fulfilled.then(() => { + return expect(module.compile()).to.be.fulfilled + .then(() => { expect(webpackMock).to.have.been.calledWith(testWebpackConfig); expect(webpackMock.compilerMock.run).to.have.been.calledOnce; return null; }); }); + it('should work with serialized compile', () => { + const testWebpackConfig = ['testconfig']; + const multiStats = { + stats: [{ + compilation: { + errors: [], + compiler: { + outputPath: 'statsMock-outputPath', + }, + }, + toString: sandbox.stub().returns('testStats'), + hasErrors: _.constant(false) + }] + }; + module.webpackConfig = testWebpackConfig; + module.multiCompile = true; + module.serializedCompile = true; + webpackMock.compilerMock.run.reset(); + webpackMock.compilerMock.run.yields(null, multiStats); + return expect(module.compile()).to.be.fulfilled + .then(() => { + expect(webpackMock).to.have.been.calledWith(testWebpackConfig); + expect(webpackMock.compilerMock.run).to.have.been.calledOnce; + return null; + }); + }); + it('should use correct stats option', () => { const testWebpackConfig = { stats: 'minimal' @@ -114,23 +141,24 @@ describe('compile', () => { outputPath: 'statsMock-outputPath' } }, - toString: sandbox.stub().returns('testStats') + toString: sandbox.stub().returns('testStats'), + hasErrors: _.constant(false) }; module.webpackConfig = testWebpackConfig; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, mockStats); - return expect(module.compile()) - .to.be.fulfilled.then(() => { - expect(webpackMock).to.have.been.calledWith(testWebpackConfig); - expect(mockStats.toString.firstCall.args).to.eql([testWebpackConfig.stats]); - module.webpackConfig = [testWebpackConfig]; - return expect(module.compile()).to.be.fulfilled; - }) - .then(() => { - expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); - expect(mockStats.toString.args).to.eql([ [testWebpackConfig.stats], [testWebpackConfig.stats] ]); - return null; - }); + return (expect(module.compile()).to.be.fulfilled) + .then(() => { + expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); + expect(mockStats.toString.firstCall.args).to.eql([testWebpackConfig.stats]); + module.webpackConfig = [testWebpackConfig]; + return (expect(module.compile()).to.be.fulfilled); + }) + .then(() => { + expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); + expect(mockStats.toString.args).to.eql([ [testWebpackConfig.stats], [testWebpackConfig.stats] ]); + return null; + }); }); }); diff --git a/tests/webpack.mock.js b/tests/webpack.mock.js index abf911e6b..5bf7194c2 100644 --- a/tests/webpack.mock.js +++ b/tests/webpack.mock.js @@ -6,12 +6,16 @@ const StatsMock = () => ({ compilation: { errors: [], compiler: { - outputPath: 'statsMock-outputPath' - } + outputPath: 'statsMock-outputPath', + }, + }, + toString: sinon.stub().returns('testStats'), + hasErrors() { + return Boolean(this.compilation.errors.length); }, - toString: sinon.stub().returns('testStats') }); + const CompilerMock = (sandbox, statsMock) => ({ run: sandbox.stub().yields(null, statsMock), watch: sandbox.stub().yields(null, statsMock), @@ -19,7 +23,7 @@ const CompilerMock = (sandbox, statsMock) => ({ beforeCompile: { tapPromise: sandbox.stub() } - } + }, }); const webpackMock = sandbox => { From 4d437738fc27f5a203820e30c4aeca4e569eef3d Mon Sep 17 00:00:00 2001 From: Andrew Sprouse Date: Fri, 14 Jun 2019 01:41:17 -0400 Subject: [PATCH 03/32] Add serializedCompile documentation --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 3cb9c3750..96c6a16f1 100644 --- a/README.md +++ b/README.md @@ -527,6 +527,15 @@ if you are trying to override the entry in webpack.config.js with other unsuppor The individual packaging needs more time at the packaging phase, but you'll get that paid back twice at runtime. +#### Individual packaging serializedCompile +```yaml +# serverless.yml +custom: + webpack: + serializedCompile: true +``` +Will run each webpack build one at a time which helps reduce memory usage and in some cases impoves overall build performance. + ## Usage ### Automatic bundling From 49b2ef812fa2f7e0226e52a51bebe1bea3f0eabf Mon Sep 17 00:00:00 2001 From: "Miguel A. Calles MBA" <44813512+miguel-a-calles-mba@users.noreply.github.com> Date: Sun, 12 Jul 2020 15:56:04 -0700 Subject: [PATCH 04/32] Update README.md --- README.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/README.md b/README.md index 96c6a16f1..66304e462 100644 --- a/README.md +++ b/README.md @@ -810,3 +810,124 @@ See [CHANGELOG.md](./CHANGELOG.md) [link-serverless-dynamodb-local]: https://www.npmjs.com/package/serverless-dynamodb-local [link-step-functions-offline]: https://www.npmjs.com/package/serverless-step-functions-offline [ico-step-functions-offline]: https://img.shields.io/npm/v/serverless-step-functions-offline.svg + +[comment]: # (Referenced issues) + +[link-135]: https://github.com/serverless-heaven/serverless-webpack/issues/135 + +[link-83]: https://github.com/serverless-heaven/serverless-webpack/pull/83 +[link-88]: https://github.com/serverless-heaven/serverless-webpack/pull/88 +[link-127]: https://github.com/serverless-heaven/serverless-webpack/pull/127 +[link-131]: https://github.com/serverless-heaven/serverless-webpack/pull/131 +[link-132]: https://github.com/serverless-heaven/serverless-webpack/pull/132 +[link-140]: https://github.com/serverless-heaven/serverless-webpack/pull/140 +[link-141]: https://github.com/serverless-heaven/serverless-webpack/issues/141 +[link-144]: https://github.com/serverless-heaven/serverless-webpack/issues/144 + +[link-11]: https://github.com/serverless-heaven/serverless-webpack/issues/11 +[link-107]: https://github.com/serverless-heaven/serverless-webpack/issues/107 +[link-129]: https://github.com/serverless-heaven/serverless-webpack/pull/129 +[link-154]: https://github.com/serverless-heaven/serverless-webpack/issues/154 +[link-159]: https://github.com/serverless-heaven/serverless-webpack/issues/159 + +[link-158]: https://github.com/serverless-heaven/serverless-webpack/issues/158 +[link-165]: https://github.com/serverless-heaven/serverless-webpack/issues/165 + +[link-193]: https://github.com/serverless-heaven/serverless-webpack/issues/193 + +[link-116]: https://github.com/serverless-heaven/serverless-webpack/issues/116 +[link-117]: https://github.com/serverless-heaven/serverless-webpack/issues/117 +[link-120]: https://github.com/serverless-heaven/serverless-webpack/issues/120 +[link-145]: https://github.com/serverless-heaven/serverless-webpack/issues/145 +[link-151]: https://github.com/serverless-heaven/serverless-webpack/issues/151 +[link-152]: https://github.com/serverless-heaven/serverless-webpack/issues/152 +[link-173]: https://github.com/serverless-heaven/serverless-webpack/issues/173 +[link-179]: https://github.com/serverless-heaven/serverless-webpack/pull/179 +[link-185]: https://github.com/serverless-heaven/serverless-webpack/pull/185 +[link-186]: https://github.com/serverless-heaven/serverless-webpack/pull/186 + +[link-202]: https://github.com/serverless-heaven/serverless-webpack/issues/202 + +[link-215]: https://github.com/serverless-heaven/serverless-webpack/issues/215 +[link-217]: https://github.com/serverless-heaven/serverless-webpack/issues/217 +[link-221]: https://github.com/serverless-heaven/serverless-webpack/pull/221 +[link-223]: https://github.com/serverless-heaven/serverless-webpack/issues/223 +[link-227]: https://github.com/serverless-heaven/serverless-webpack/pull/227 +[link-234]: https://github.com/serverless-heaven/serverless-webpack/pull/234 + +[link-245]: https://github.com/serverless-heaven/serverless-webpack/issues/245 + +[link-251]: https://github.com/serverless-heaven/serverless-webpack/issues/251 + +[link-126]: https://github.com/serverless-heaven/serverless-webpack/issues/126 +[link-247]: https://github.com/serverless-heaven/serverless-webpack/issues/247 +[link-250]: https://github.com/serverless-heaven/serverless-webpack/issues/250 +[link-254]: https://github.com/serverless-heaven/serverless-webpack/pull/254 +[link-260]: https://github.com/serverless-heaven/serverless-webpack/issues/260 +[link-264]: https://github.com/serverless-heaven/serverless-webpack/pull/264 +[link-265]: https://github.com/serverless-heaven/serverless-webpack/pull/265 + +[link-272]: https://github.com/serverless-heaven/serverless-webpack/issues/272 +[link-278]: https://github.com/serverless-heaven/serverless-webpack/pull/278 +[link-279]: https://github.com/serverless-heaven/serverless-webpack/issues/279 +[link-276]: https://github.com/serverless-heaven/serverless-webpack/issues/276 +[link-269]: https://github.com/serverless-heaven/serverless-webpack/issues/269 + +[link-263]: https://github.com/serverless-heaven/serverless-webpack/issues/263 + +[link-286]: https://github.com/serverless-heaven/serverless-webpack/issues/286 + +[link-315]: https://github.com/serverless-heaven/serverless-webpack/issues/315 +[link-316]: https://github.com/serverless-heaven/serverless-webpack/issues/316 +[link-253]: https://github.com/serverless-heaven/serverless-webpack/issues/253 +[link-317]: https://github.com/serverless-heaven/serverless-webpack/pull/317 +[link-321]: https://github.com/serverless-heaven/serverless-webpack/pull/321 + +[link-313]: https://github.com/serverless-heaven/serverless-webpack/pull/313 +[link-326]: https://github.com/serverless-heaven/serverless-webpack/pull/326 +[link-329]: https://github.com/serverless-heaven/serverless-webpack/issues/329 + +[link-232]: https://github.com/serverless-heaven/serverless-webpack/issues/232 +[link-331]: https://github.com/serverless-heaven/serverless-webpack/issues/331 +[link-328]: https://github.com/serverless-heaven/serverless-webpack/pull/328 +[link-336]: https://github.com/serverless-heaven/serverless-webpack/pull/336 +[link-337]: https://github.com/serverless-heaven/serverless-webpack/pull/337 + +[link-275]: https://github.com/serverless-heaven/serverless-webpack/issues/275 +[link-286]: https://github.com/serverless-heaven/serverless-webpack/issues/286 +[link-341]: https://github.com/serverless-heaven/serverless-webpack/issues/341 +[link-342]: https://github.com/serverless-heaven/serverless-webpack/issues/342 +[link-343]: https://github.com/serverless-heaven/serverless-webpack/issues/343 + +[link-349]: https://github.com/serverless-heaven/serverless-webpack/issues/349 +[link-354]: https://github.com/serverless-heaven/serverless-webpack/pull/354 +[link-355]: https://github.com/serverless-heaven/serverless-webpack/pull/355 + +[link-309]: https://github.com/serverless-heaven/serverless-webpack/issues/309 +[link-365]: https://github.com/serverless-heaven/serverless-webpack/pull/365 +[link-373]: https://github.com/serverless-heaven/serverless-webpack/pull/373 + +[link-370]: https://github.com/serverless-heaven/serverless-webpack/issues/370 + +[link-379]: https://github.com/serverless-heaven/serverless-webpack/issues/379 +[link-382]: https://github.com/serverless-heaven/serverless-webpack/pull/382 +[link-384]: https://github.com/serverless-heaven/serverless-webpack/pull/384 + +[link-393]: https://github.com/serverless-heaven/serverless-webpack/issues/393 +[link-412]: https://github.com/serverless-heaven/serverless-webpack/issues/412 +[link-418]: https://github.com/serverless-heaven/serverless-webpack/issues/418 + +[link-453]: https://github.com/serverless-heaven/serverless-webpack/issues/453 +[link-467]: https://github.com/serverless-heaven/serverless-webpack/issues/467 +[link-449]: https://github.com/serverless-heaven/serverless-webpack/issues/449 +[link-465]: https://github.com/serverless-heaven/serverless-webpack/issues/465 +[link-480]: https://github.com/serverless-heaven/serverless-webpack/issues/480 +[link-429]: https://github.com/serverless-heaven/serverless-webpack/pull/429 +[link-433]: https://github.com/serverless-heaven/serverless-webpack/issues/433 +[link-471]: https://github.com/serverless-heaven/serverless-webpack/issues/471 +[link-472]: https://github.com/serverless-heaven/serverless-webpack/pull/472 + +[link-505]: https://github.com/serverless-heaven/serverless-webpack/issues/505 +[link-499]: https://github.com/serverless-heaven/serverless-webpack/issues/499 +[link-496]: https://github.com/serverless-heaven/serverless-webpack/pull/496 + From 468cf394bbdc7fb1386b754c6e885d080e207f9b Mon Sep 17 00:00:00 2001 From: "Miguel A. Calles MBA" <44813512+miguel-a-calles-mba@users.noreply.github.com> Date: Sun, 12 Jul 2020 15:56:17 -0700 Subject: [PATCH 05/32] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 66304e462..4edb7264f 100644 --- a/README.md +++ b/README.md @@ -930,4 +930,3 @@ See [CHANGELOG.md](./CHANGELOG.md) [link-505]: https://github.com/serverless-heaven/serverless-webpack/issues/505 [link-499]: https://github.com/serverless-heaven/serverless-webpack/issues/499 [link-496]: https://github.com/serverless-heaven/serverless-webpack/pull/496 - From 9b2fe1aeafc19d4f888c6fcdfc4f5bfdf8445a40 Mon Sep 17 00:00:00 2001 From: D See Ker Date: Sat, 25 Jan 2020 00:10:12 +0000 Subject: [PATCH 06/32] Option to exclude files using regular expression --- README.md | 15 ++++++++++++++- lib/Configuration.js | 4 ++++ lib/packageModules.js | 4 +++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4edb7264f..a0fdda9a8 100644 --- a/README.md +++ b/README.md @@ -439,7 +439,7 @@ If you have a project structure that uses something like `index.js` and a co-located `index.test.js` then you have likely seen an error like: `WARNING: More than one matching handlers found for index. Using index.js` -This config option allows you to exlcude files that match a glob from function +This config option allows you to exclude files that match a glob from function resolution. Just add: `excludeFiles: **/*.test.js` (with whatever glob you want to exclude). @@ -452,6 +452,19 @@ custom: This is also useful for projects that use TypeScript. +#### Exclude Files with Regular Expression + +This config option allows you to filter files that match a regex pattern before +adding to the zip file. Just add: `excludeRegex: \.ts|test|\.map` (with whatever +regex you want to exclude). + +```yaml +# serverless.yml +custom: + webpack: + excludeRegex: \.ts|test|\.map +``` + #### Keep output directory after packaging You can keep the output directory (defaults to `.webpack`) from being removed diff --git a/lib/Configuration.js b/lib/Configuration.js index 2022ca913..d2fea80c7 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -53,6 +53,10 @@ class Configuration { get excludeFiles() { return this._config.excludeFiles; } + + get excludeRegex() { + return this._config.excludeRegex; + } get packager() { return this._config.packager; diff --git a/lib/packageModules.js b/lib/packageModules.js index 5026f2c29..ff7bda568 100644 --- a/lib/packageModules.js +++ b/lib/packageModules.js @@ -34,12 +34,14 @@ function zip(directory, name) { const output = fs.createWriteStream(artifactFilePath); - const files = glob.sync('**', { + let files = glob.sync('**', { cwd: directory, dot: true, silent: true, follow: true }); + + if (this.configuration.excludeRegex) files = files.filter(f => f.match(this.configuration.excludeRegex) === null); if (_.isEmpty(files)) { const error = new this.serverless.classes.Error('Packaging: No files found'); From 01d8d138020ed745faae4b789389883ff52713aa Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Fri, 24 Jul 2020 11:15:22 +0200 Subject: [PATCH 07/32] Add some tests & fix linter --- README.md | 4 +-- lib/packageModules.js | 6 +++-- tests/packageModules.test.js | 52 +++++++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a0fdda9a8..b02820e20 100644 --- a/README.md +++ b/README.md @@ -455,14 +455,14 @@ This is also useful for projects that use TypeScript. #### Exclude Files with Regular Expression This config option allows you to filter files that match a regex pattern before -adding to the zip file. Just add: `excludeRegex: \.ts|test|\.map` (with whatever +adding to the zip file. Just add: `excludeRegex: \.ts|test|\.map` (with whatever regex you want to exclude). ```yaml # serverless.yml custom: webpack: - excludeRegex: \.ts|test|\.map + excludeRegex: /\.ts|test|\.map/ ``` #### Keep output directory after packaging diff --git a/lib/packageModules.js b/lib/packageModules.js index ff7bda568..4d6eac5f2 100644 --- a/lib/packageModules.js +++ b/lib/packageModules.js @@ -40,8 +40,10 @@ function zip(directory, name) { silent: true, follow: true }); - - if (this.configuration.excludeRegex) files = files.filter(f => f.match(this.configuration.excludeRegex) === null); + + if (this.configuration.excludeRegex) { + files = _.filter(files, f => f.match(this.configuration.excludeRegex) === null); + } if (_.isEmpty(files)) { const error = new this.serverless.classes.Error('Packaging: No files found'); diff --git a/tests/packageModules.test.js b/tests/packageModules.test.js index 92c15fc8b..bfd11d839 100644 --- a/tests/packageModules.test.js +++ b/tests/packageModules.test.js @@ -7,6 +7,7 @@ const path = require('path'); const sinon = require('sinon'); const mockery = require('mockery'); const Serverless = require('serverless'); +const Configuration = require('../lib/Configuration'); // Mocks const fsMockFactory = require('./mocks/fs.mock'); @@ -73,7 +74,8 @@ describe('packageModules', () => { { serverless, options: {}, - webpackOutputPath: '.webpack' + webpackOutputPath: '.webpack', + configuration: new Configuration() }, baseModule ); @@ -327,6 +329,54 @@ describe('packageModules', () => { module.compileStats = stats; return expect(module.packageModules()).to.be.rejectedWith('Packaging: No files found'); }); + + it('should reject if no files are found because all files are excluded using regex', () => { + module.configuration = new Configuration({ + webpack: { + excludeRegex: /.*/ + } + }); + + // Test data + const stats = { + stats: [ + { + compilation: { + compiler: { + outputPath: '/my/Service/Path/.webpack/service' + } + } + } + ] + }; + const files = [ 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' ]; + const allFunctions = [ 'func1', 'func2' ]; + const func1 = { + handler: 'src/handler1', + events: [] + }; + const func2 = { + handler: 'src/handler2', + events: [] + }; + // Serverless behavior + sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path'); + getVersionStub.returns('1.18.0'); + getServiceObjectStub.returns({ + name: 'test-service' + }); + getAllFunctionsStub.returns(allFunctions); + getFunctionStub.withArgs('func1').returns(func1); + getFunctionStub.withArgs('func2').returns(func2); + // Mock behavior + globMock.sync.returns(files); + fsMock._streamMock.on.withArgs('open').yields(); + fsMock._streamMock.on.withArgs('close').yields(); + fsMock._statMock.isDirectory.returns(false); + + module.compileStats = stats; + return expect(module.packageModules()).to.be.rejectedWith('Packaging: No files found'); + }); }); describe('with individual packaging', () => { From 789f8a34b84f01a5b6386cfd99b938fb16a3358f Mon Sep 17 00:00:00 2001 From: Emilien Escalle Date: Sun, 11 Nov 2018 16:29:48 +0100 Subject: [PATCH 08/32] Improve cleanup process --- lib/cleanup.js | 14 ++++++++--- tests/cleanup.test.js | 57 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/lib/cleanup.js b/lib/cleanup.js index 9173529ff..9664c9bb5 100644 --- a/lib/cleanup.js +++ b/lib/cleanup.js @@ -1,20 +1,26 @@ 'use strict'; +const _ = require('lodash'); const BbPromise = require('bluebird'); const fse = require('fs-extra'); module.exports = { cleanup() { const webpackOutputPath = this.webpackOutputPath; - const keepOutputDirectory = this.keepOutputDirectory; + const cli = this.options.verbose ? this.serverless.cli : { log: _.noop }; + if (!keepOutputDirectory) { - this.options.verbose && this.serverless.cli.log(`Remove ${webpackOutputPath}`); + cli.log(`Remove ${webpackOutputPath}`); if (this.serverless.utils.dirExistsSync(webpackOutputPath)) { - fse.removeSync(webpackOutputPath); + // Remove async to speed up process + fse + .remove(webpackOutputPath) + .then(() => cli.log(`Removing ${webpackOutputPath} done`)) + .catch(error => cli.log(`Error occurred while removing ${webpackOutputPath}: ${error}`)); } } else { - this.options.verbose && this.serverless.cli.log(`Keeping ${webpackOutputPath}`); + cli.log(`Keeping ${webpackOutputPath}`); } return BbPromise.resolve(); diff --git a/tests/cleanup.test.js b/tests/cleanup.test.js index 2be4cd3a2..dec18893a 100644 --- a/tests/cleanup.test.js +++ b/tests/cleanup.test.js @@ -14,7 +14,7 @@ const expect = chai.expect; const FseMock = sandbox => ({ copy: sandbox.stub(), - removeSync: sandbox.stub() + remove: sandbox.stub() }); describe('cleanup', () => { @@ -47,6 +47,7 @@ describe('cleanup', () => { serverless = new Serverless(); serverless.cli = { log: sandbox.stub(), + error: sandbox.stub(), consoleLog: sandbox.stub() }; dirExistsSyncStub = sandbox.stub(serverless.utils, 'dirExistsSync'); @@ -54,7 +55,9 @@ describe('cleanup', () => { module = _.assign( { serverless, - options: {}, + options: { + verbose: true + }, webpackOutputPath: 'my/Output/Path' }, baseModule @@ -64,42 +67,78 @@ describe('cleanup', () => { afterEach(() => { // This will reset the webpackMock too sandbox.restore(); + fseMock.remove.reset(); + serverless.cli.log.reset(); }); it('should remove output dir if it exists', () => { dirExistsSyncStub.returns(true); - fseMock.removeSync.reset(); + fseMock.remove.resolves(true); return expect(module.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.have.been.calledOnce; expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path'); - expect(fseMock.removeSync).to.have.been.calledOnce; + expect(fseMock.remove).to.have.been.calledOnce; + expect(serverless.cli.log).to.have.been.calledWith('Removing my/Output/Path done'); return null; }); }); - it('should not call removeSync if output dir does not exists', () => { + it('should log nothing is verbose is false', () => { + dirExistsSyncStub.returns(true); + fseMock.remove.resolves(true); + + module = _.assign( + { + serverless, + options: { + verbose: false + }, + webpackOutputPath: 'my/Output/Path' + }, + baseModule + ); + + return expect(module.cleanup()).to.be.fulfilled.then(() => { + expect(dirExistsSyncStub).to.have.been.calledOnce; + expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path'); + expect(fseMock.remove).to.have.been.calledOnce; + expect(serverless.cli.log).not.to.have.been.called; + return null; + }); + }); + + it('should log an error if it occurs', () => { + dirExistsSyncStub.returns(true); + fseMock.remove.rejects('remove error'); + + return expect(module.cleanup()).to.be.fulfilled.then(() => { + expect(serverless.cli.log).to.have.been.calledWith('Error occurred while removing my/Output/Path: remove error'); + + return null; + }); + }); + + it('should not call remove if output dir does not exists', () => { dirExistsSyncStub.returns(false); - fseMock.removeSync.reset(); return expect(module.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.have.been.calledOnce; expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path'); - expect(fseMock.removeSync).to.not.have.been.called; + expect(fseMock.remove).to.not.have.been.called; return null; }); }); it('should keep output dir if keepOutputDir = true', () => { dirExistsSyncStub.returns(true); - fseMock.removeSync.reset(); const configuredModule = _.assign({}, module, { keepOutputDirectory: true }); return expect(configuredModule.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.not.have.been.calledOnce; - expect(fseMock.removeSync).to.not.have.been.called; + expect(fseMock.remove).to.not.have.been.called; return null; }); }); From 678eaa6a44249ef7a3e6c84a65b25e788f93b61c Mon Sep 17 00:00:00 2001 From: Bryan Goldstein Date: Thu, 25 Jun 2020 18:32:27 -0400 Subject: [PATCH 09/32] fix for dependencies with no version detected fixes #414 --- lib/packagers/yarn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packagers/yarn.js b/lib/packagers/yarn.js index d1dcd74d9..8895f5cbf 100644 --- a/lib/packagers/yarn.js +++ b/lib/packagers/yarn.js @@ -117,7 +117,7 @@ class Yarn { static install(cwd, packagerOptions) { const command = /^win/.test(process.platform) ? 'yarn.cmd' : 'yarn'; - const args = [ 'install', '--frozen-lockfile', '--non-interactive' ]; + const args = [ 'install', '--pure-lockfile', '--non-interactive' ]; // Convert supported packagerOptions if (packagerOptions.ignoreScripts) { From 19a0088bf268cdfa32df5363817536c790b5224b Mon Sep 17 00:00:00 2001 From: Bryan Goldstein Date: Thu, 25 Jun 2020 18:48:35 -0400 Subject: [PATCH 10/32] fix tests --- lib/packagers/yarn.test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/packagers/yarn.test.js b/lib/packagers/yarn.test.js index 52445ad4a..8ec580988 100644 --- a/lib/packagers/yarn.test.js +++ b/lib/packagers/yarn.test.js @@ -134,11 +134,11 @@ describe('yarn', () => { acorn@^2.1.0, acorn@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" - + acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - + otherModule@file:../../otherModule/the-new-version: version "1.2.0" @@ -162,7 +162,7 @@ describe('yarn', () => { request "^2.83.0" ulid "^0.1.0" uuid "^3.1.0" - + acorn@^5.0.0, acorn@^5.5.0: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" @@ -172,11 +172,11 @@ describe('yarn', () => { acorn@^2.1.0, acorn@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" - + acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - + otherModule@file:../../project/../../otherModule/the-new-version: version "1.2.0" @@ -200,7 +200,7 @@ describe('yarn', () => { request "^2.83.0" ulid "^0.1.0" uuid "^3.1.0" - + acorn@^5.0.0, acorn@^5.5.0: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" @@ -218,7 +218,7 @@ describe('yarn', () => { expect(Utils.spawnProcess).to.have.been.calledOnce; expect(Utils.spawnProcess).to.have.been.calledWithExactly( sinon.match(/^yarn/), - [ 'install', '--frozen-lockfile', '--non-interactive' ], + [ 'install', '--pure-lockfile', '--non-interactive' ], { cwd: 'myPath' } @@ -234,7 +234,7 @@ describe('yarn', () => { expect(Utils.spawnProcess).to.have.been.calledOnce; expect(Utils.spawnProcess).to.have.been.calledWithExactly( sinon.match(/^yarn/), - [ 'install', '--frozen-lockfile', '--non-interactive', '--ignore-scripts' ], + [ 'install', '--pure-lockfile', '--non-interactive', '--ignore-scripts' ], { cwd: 'myPath' } From ecf6c2b76d0600005a0be7fee3016b9037d8a130 Mon Sep 17 00:00:00 2001 From: "Miguel A. Calles MBA" <44813512+miguel-a-calles-mba@users.noreply.github.com> Date: Sun, 2 Aug 2020 09:05:46 -0700 Subject: [PATCH 11/32] Update yarn.js --- lib/packagers/yarn.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/packagers/yarn.js b/lib/packagers/yarn.js index 8895f5cbf..caab20dcf 100644 --- a/lib/packagers/yarn.js +++ b/lib/packagers/yarn.js @@ -143,3 +143,4 @@ class Yarn { } module.exports = Yarn; + From 32d5071518c7b3d5372703d6105c1be9b03bc645 Mon Sep 17 00:00:00 2001 From: "Miguel A. Calles MBA" <44813512+miguel-a-calles-mba@users.noreply.github.com> Date: Sun, 2 Aug 2020 09:05:57 -0700 Subject: [PATCH 12/32] Update yarn.js --- lib/packagers/yarn.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/packagers/yarn.js b/lib/packagers/yarn.js index caab20dcf..8895f5cbf 100644 --- a/lib/packagers/yarn.js +++ b/lib/packagers/yarn.js @@ -143,4 +143,3 @@ class Yarn { } module.exports = Yarn; - From fb877e4ef266568ba9d50f6d850719ef0eba98a2 Mon Sep 17 00:00:00 2001 From: V Date: Fri, 3 Jul 2020 21:30:03 +0800 Subject: [PATCH 13/32] Update compile.js Use `.map(..., { concurrency })` instead of `.mapSeries(...)` --- lib/compile.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/compile.js b/lib/compile.js index 683242f7a..9df3716c7 100644 --- a/lib/compile.js +++ b/lib/compile.js @@ -39,9 +39,9 @@ function webpackCompile(config, logStats) { }); } -function webpackCompileSerial(configs, logStats) { +function webpackConcurrentCompile(configs, logStats, concurrency) { return BbPromise - .mapSeries(configs, config => webpackCompile(config, logStats)) + .map(configs, config => webpackCompile(config, logStats), { concurrency }) .then(stats => _.flatten(stats)); } @@ -51,8 +51,9 @@ module.exports = { const configs = ensureArray(this.webpackConfig); const logStats = getStatsLogger(configs[0].stats, this.serverless.cli.consoleLog); + const concurrency = this.serializedCompile === true ? 1 : this.serializedCompile; - return (this.serializedCompile ? webpackCompileSerial : webpackCompile)(configs, logStats) + return webpackConcurrentCompile(configs, logStats, concurrency) .then(stats => { this.compileStats = { stats }; return BbPromise.resolve(); From 4af95b6476aeb3664b91e5b7f3e6bd2c07321245 Mon Sep 17 00:00:00 2001 From: V Date: Fri, 3 Jul 2020 21:44:04 +0800 Subject: [PATCH 14/32] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b02820e20..7e533218e 100644 --- a/README.md +++ b/README.md @@ -540,12 +540,12 @@ if you are trying to override the entry in webpack.config.js with other unsuppor The individual packaging needs more time at the packaging phase, but you'll get that paid back twice at runtime. -#### Individual packaging serializedCompile +#### Individual packaging concurrency ```yaml # serverless.yml custom: webpack: - serializedCompile: true + concurrency: 5 ``` Will run each webpack build one at a time which helps reduce memory usage and in some cases impoves overall build performance. From d1ce81489e19be8ed51db61f6520f9fbf6c4124a Mon Sep 17 00:00:00 2001 From: V Date: Fri, 3 Jul 2020 21:44:53 +0800 Subject: [PATCH 15/32] Rename to concurrency --- lib/Configuration.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Configuration.js b/lib/Configuration.js index d2fea80c7..84326e074 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -15,7 +15,7 @@ const DefaultConfig = { packagerOptions: {}, keepOutputDirectory: false, config: null, - serializedCompile: false + concurrency: undefined }; class Configuration { @@ -78,8 +78,8 @@ class Configuration { return this._config.keepOutputDirectory; } - get serializedCompile() { - return this._config.serializedCompile; + get concurrency() { + return this._config.concurrency; } toJSON() { From 883ea076d30061c17b2e51a19ba8ac1547f1f069 Mon Sep 17 00:00:00 2001 From: V Date: Fri, 3 Jul 2020 21:45:40 +0800 Subject: [PATCH 16/32] Update Configuration.test.js --- lib/Configuration.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Configuration.test.js b/lib/Configuration.test.js index 4324b4bde..1309fdbfd 100644 --- a/lib/Configuration.test.js +++ b/lib/Configuration.test.js @@ -20,7 +20,7 @@ describe('Configuration', () => { packagerOptions: {}, keepOutputDirectory: false, config: null, - serializedCompile: false + concurrency: undefined }; }); @@ -70,7 +70,7 @@ describe('Configuration', () => { packagerOptions: {}, keepOutputDirectory: false, config: null, - serializedCompile: false + concurrency: undefined }); }); }); @@ -91,7 +91,7 @@ describe('Configuration', () => { packagerOptions: {}, keepOutputDirectory: false, config: null, - serializedCompile: false + concurrency: undefined }); }); @@ -111,7 +111,7 @@ describe('Configuration', () => { packagerOptions: {}, keepOutputDirectory: false, config: null, - serializedCompile: false + concurrency: undefined }); }); }); From f8db180e7e8eacaf9ab5927f4c46f04ab6c96750 Mon Sep 17 00:00:00 2001 From: V Date: Fri, 3 Jul 2020 21:47:12 +0800 Subject: [PATCH 17/32] Update validate.js --- lib/validate.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/validate.js b/lib/validate.js index 80d8999cc..4908ea0d9 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -190,8 +190,8 @@ module.exports = { // In case of individual packaging we have to create a separate config for each function if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) { this.multiCompile = true; - this.serializedCompile = this.configuration.serializedCompile; - this.options.verbose && this.serverless.cli.log(`Using ${this.serializedCompile ? 'serialized' : 'multi'}-compile (individual packaging)`); + this.concurrency = this.configuration.concurrency; + this.options.verbose && this.serverless.cli.log(`Using ${this.concurrency ? 'concurrent' : 'multi'}-compile (individual packaging)`); if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) { return BbPromise.reject( From df63d720d056a704f0e49be70dab9f164a943207 Mon Sep 17 00:00:00 2001 From: V Date: Fri, 3 Jul 2020 21:49:03 +0800 Subject: [PATCH 18/32] Update compile.test.js --- tests/compile.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile.test.js b/tests/compile.test.js index 58f682029..f0de93576 100644 --- a/tests/compile.test.js +++ b/tests/compile.test.js @@ -103,7 +103,7 @@ describe('compile', () => { }); }); - it('should work with serialized compile', () => { + it('should work with concurrent compile', () => { const testWebpackConfig = ['testconfig']; const multiStats = { stats: [{ @@ -119,7 +119,7 @@ describe('compile', () => { }; module.webpackConfig = testWebpackConfig; module.multiCompile = true; - module.serializedCompile = true; + module.concurrency = 1; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, multiStats); return expect(module.compile()).to.be.fulfilled From 874a2410bd6774b92dc7654d773c793b6255bd6e Mon Sep 17 00:00:00 2001 From: V Date: Fri, 3 Jul 2020 21:55:50 +0800 Subject: [PATCH 19/32] bluebird doesn't like undefined concurrency --- lib/compile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compile.js b/lib/compile.js index 9df3716c7..40e6a298f 100644 --- a/lib/compile.js +++ b/lib/compile.js @@ -51,7 +51,7 @@ module.exports = { const configs = ensureArray(this.webpackConfig); const logStats = getStatsLogger(configs[0].stats, this.serverless.cli.consoleLog); - const concurrency = this.serializedCompile === true ? 1 : this.serializedCompile; + const concurrency = this.concurrency === undefined ? Infinity : this.concurrency; return webpackConcurrentCompile(configs, logStats, concurrency) .then(stats => { From 23bb9a38b3a09ca2e8a5fe19aaa2814e0002776a Mon Sep 17 00:00:00 2001 From: Vicary Archangel Date: Sun, 4 Oct 2020 21:11:23 +0800 Subject: [PATCH 20/32] Support icloud drive --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e701029f9..88ece127c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules +node_modules.nosync dist .webpack .serverless From 2fdc3ebea704911a6166f213f8dc05516e7289e7 Mon Sep 17 00:00:00 2001 From: Andrew Sprouse Date: Fri, 14 Jun 2019 01:21:23 -0400 Subject: [PATCH 21/32] Serialized compile to address #299 --- lib/Configuration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Configuration.js b/lib/Configuration.js index 84326e074..09b346856 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -53,7 +53,7 @@ class Configuration { get excludeFiles() { return this._config.excludeFiles; } - + get excludeRegex() { return this._config.excludeRegex; } From 6ab5e920abd4d1103ba66a5643efddd120217559 Mon Sep 17 00:00:00 2001 From: Vicary Date: Sun, 4 Oct 2020 21:26:56 +0800 Subject: [PATCH 22/32] compatible with serialized compile --- lib/Configuration.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Configuration.js b/lib/Configuration.js index 09b346856..ca9a523eb 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -79,7 +79,11 @@ class Configuration { } get concurrency() { - return this._config.concurrency; + if (this._config.concurrency !== undefined) { + return this._config.concurrency; + } else if (this._config.serializedCompile === true) { + return 1; + } } toJSON() { From ca76a2510ea065b9b37a20fc336483c6f7b2bd5d Mon Sep 17 00:00:00 2001 From: Vicary Date: Sun, 4 Oct 2020 21:27:17 +0800 Subject: [PATCH 23/32] audit fix --- package-lock.json | 135 ++++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 53 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76fa462c6..2a92be57d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -894,8 +894,8 @@ "chalk": "^2.4.1", "https-proxy-agent": "^4.0.0", "is-docker": "^1.1.0", - "isomorphic-fetch": "^2.2.1", "jwt-decode": "^2.2.0", + "node-fetch": "^2.6.1", "opn": "^5.5.0", "querystring": "^0.2.0", "ramda": "^0.25.0", @@ -975,9 +975,9 @@ } }, "@serverless/utils-china": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/@serverless/utils-china/-/utils-china-0.1.27.tgz", - "integrity": "sha512-ZQDTtmFBD2xl23YFFMVOTmqsgqtcxk9WKBGdixZ3ZY2MxAjrNJvBE0vPCRsYrQCs0I+TzdPDRIPSrOUJh7cpiw==", + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/@serverless/utils-china/-/utils-china-0.1.28.tgz", + "integrity": "sha512-nxMBES1wR+U1U8UWaWd7CwKmoY18SRHT6h39ux8YGXgxeRd9pqKB4/TTLX4hHYMsqHteXufpFZQIhl0aGf9oww==", "dev": true, "requires": { "@tencent-sdk/capi": "^0.2.17", @@ -1010,9 +1010,9 @@ "dev": true }, "@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", + "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -1152,18 +1152,18 @@ "integrity": "sha512-aYNbO+FZ/3KGeQCEkNhHFRIzBOUgc7QvcVNKXbfnhDkSfwUv91JsQQa10rDgKSTSLkXZ1UIyPe4FJJNVgw1xWQ==", "dev": true }, - "@types/object-assign": { - "version": "4.0.30", - "resolved": "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz", - "integrity": "sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI=", - "dev": true - }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/object-assign": { + "version": "4.0.30", + "resolved": "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz", + "integrity": "sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI=", + "dev": true + }, "@types/request": { "version": "2.48.5", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", @@ -2865,9 +2865,9 @@ } }, "dayjs": { - "version": "1.8.35", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.35.tgz", - "integrity": "sha512-isAbIEenO4ilm6f8cpqvgjZCsuerDAz2Kb7ri201AiNn58aqXuaLJEnCtfIMdCvERZHNGRY5lDMTr/jdAnKSWQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.9.1.tgz", + "integrity": "sha512-01NCTBg8cuMJG1OQc6PR7T66+AFYiPwgDvdJmvJBn29NGzIG+DIFxPLNjHzwz3cpFIvG+NcwIjP9hSaPVoOaDg==", "dev": true }, "debug": { @@ -3583,20 +3583,20 @@ }, "dependencies": { "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.0", + "object.assign": "^4.1.1", "string.prototype.trimend": "^1.0.1", "string.prototype.trimstart": "^1.0.1" } @@ -3619,9 +3619,9 @@ "dev": true }, "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", "dev": true }, "is-regex": { @@ -3638,6 +3638,40 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true + }, + "object.assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } } } }, @@ -6009,9 +6043,9 @@ } }, "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", "dev": true }, "is-builtin-module": { @@ -10656,9 +10690,9 @@ "dev": true }, "string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.0.tgz", + "integrity": "sha512-NGZHq3nkSXVtGZXTBjFru3MNfoZyIzN25T7BmvdgnSC0LCJczAGLLMQLyjywSIaAoqSemgLzBRHOsnrHbt60+Q==", "dev": true }, "string-width": { @@ -10682,20 +10716,20 @@ }, "dependencies": { "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.0", + "object.assign": "^4.1.1", "string.prototype.trimend": "^1.0.1", "string.prototype.trimstart": "^1.0.1" } @@ -10920,10 +10954,16 @@ "has-flag": "^3.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.4.tgz", + "integrity": "sha512-IIfEAUx5QlODLblLrGTTLJA7Tk0iLSGBvgY8essPRVNGHAzThujww1YqHLs6h3HfTg55h++RzLHH5Xw/rfv+mg==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -10938,17 +10978,6 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", From a234211d4d8047b7bbfba4597dc8c2808d7f6004 Mon Sep 17 00:00:00 2001 From: Vicary Date: Sun, 4 Oct 2020 21:27:59 +0800 Subject: [PATCH 24/32] docs for compatibility with serilized-compile --- README.md | 115 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 7e533218e..567ccf82d 100644 --- a/README.md +++ b/README.md @@ -15,25 +15,25 @@ and much more! ## Highlights -* Configuration possibilities range from zero-config to fully customizable -* Support of `serverless package`, `serverless deploy` and `serverless deploy function` -* Support of `serverless invoke local` and `serverless invoke local --watch` -* Support of `serverless run` and `serverless run --watch` -* Integrates with [`serverless-offline`][link-serverless-offline] to simulate local API Gateway endpoints -* When enabled in your service configuration, functions are packaged and compiled -individually, resulting in smaller Lambda packages that contain only the code and -dependencies needed to run the function. This allows the plugin to fully utilize -WebPack's [Tree-Shaking][link-webpack-tree] optimization. -* Webpack version 3, 4 and 5 support -* Support NPM and Yarn for packaging -* Support asynchronous webpack configuration +- Configuration possibilities range from zero-config to fully customizable +- Support of `serverless package`, `serverless deploy` and `serverless deploy function` +- Support of `serverless invoke local` and `serverless invoke local --watch` +- Support of `serverless run` and `serverless run --watch` +- Integrates with [`serverless-offline`][link-serverless-offline] to simulate local API Gateway endpoints +- When enabled in your service configuration, functions are packaged and compiled + individually, resulting in smaller Lambda packages that contain only the code and + dependencies needed to run the function. This allows the plugin to fully utilize + WebPack's [Tree-Shaking][link-webpack-tree] optimization. +- Webpack version 3, 4 and 5 support +- Support NPM and Yarn for packaging +- Support asynchronous webpack configuration ## Recent improvements and important changes for 5.x -* Support Yarn -* Support Webpack 4 and 5 -* Cleaned up configuration. You should now use a `custom.webpack` object to configure everything relevant for the plugin. The old configuration still works but will be removed in the next major release. For details see below. -* Added support for asynchronous webpack configuration +- Support Yarn +- Support Webpack 4 and 5 +- Cleaned up configuration. You should now use a `custom.webpack` object to configure everything relevant for the plugin. The old configuration still works but will be removed in the next major release. For details see below. +- Added support for asynchronous webpack configuration For the complete release notes see the end of this document. @@ -59,9 +59,9 @@ See the sections below for detailed descriptions of the settings. The defaults a ```yaml custom: webpack: - webpackConfig: 'webpack.config.js' # Name of webpack configuration file - includeModules: false # Node modules configuration for packaging - packager: 'npm' # Packager that will be used to package your external modules + webpackConfig: 'webpack.config.js' # Name of webpack configuration file + includeModules: false # Node modules configuration for packaging + packager: 'npm' # Packager that will be used to package your external modules excludeFiles: src/**/*.test.js # Provide a glob for files to ignore ``` @@ -92,6 +92,7 @@ module.exports = { Alternatively the Webpack configuration can export an asynchronous object (e.g. a promise or async function) which will be awaited by the plugin and resolves to the final configuration object. This is useful if the confguration depends on asynchronous functions, for example, defining the AccountId of the current aws user inside AWS lambda@edge which does not support defining normal process environment variables. A basic Webpack promise configuration might look like this: + ```js // Version if the local Node.js version supports async/await // webpack.config.js @@ -115,6 +116,7 @@ module.exports = (async () => { }; })(); ``` + ```js // Version with promises // webpack.config.js @@ -212,6 +214,7 @@ This allows to set properties in the webpack configuration differently depending if the lambda code is run on the local machine or deployed. A sample is to set the compile mode with Webpack 4: + ``` mode: slsw.lib.webpack.isLocal ? "development" : "production" ``` @@ -232,8 +235,8 @@ module.exports = { output: { libraryTarget: 'commonjs', path: path.resolve(__dirname, '.webpack'), - filename: '[name].js', - }, + filename: '[name].js' + } // ... }; ``` @@ -250,12 +253,11 @@ module.exports = { // ... stats: 'minimal' // ... -} +}; ``` All the stats config can be found in [webpack's documentation][link-webpack-stats] - ### Node modules / externals By default, the plugin will try to bundle all dependencies. However, you don't @@ -269,13 +271,13 @@ option in `serverless.yml`: ```js // webpack.config.js -var nodeExternals = require('webpack-node-externals') +var nodeExternals = require('webpack-node-externals'); module.exports = { // we use webpack-node-externals to excludes all node deps. // You can manually set the externals too. - externals: [nodeExternals()], -} + externals: [nodeExternals()] +}; ``` ```yaml @@ -285,7 +287,6 @@ custom: includeModules: true # enable auto-packing of external modules ``` - All modules stated in `externals` will be excluded from bundled files. If an excluded module is stated as `dependencies` in `package.json` and it is used by the webpack chunk, it will be packed into the Serverless artifact under the `node_modules` directory. @@ -300,6 +301,7 @@ custom: includeModules: packagePath: '../package.json' # relative path to custom package.json file. ``` + > Note that only relative path is supported at the moment. #### Runtime dependencies @@ -337,8 +339,8 @@ or 'yarn' and defaults to using npm when not set. # serverless.yml custom: webpack: - packager: 'yarn' # Defaults to npm - packagerOptions: {} # Optional, depending on the selected packager + packager: 'yarn' # Defaults to npm + packagerOptions: {} # Optional, depending on the selected packager ``` You should select the packager, that you use to develop your projects, because only @@ -361,8 +363,8 @@ Using yarn will switch the whole packaging pipeline to use yarn, so does it use The yarn packager supports the following `packagerOptions`: -| Option | Type | Default | Description | -|---------------|------|---------|-------------| +| Option | Type | Default | Description | +| ------------- | ---- | ------- | --------------------------------------------------- | | ignoreScripts | bool | true | Do not execute package.json hook scripts on install | ##### Common packager options @@ -516,10 +518,9 @@ service: ```yaml # serverless.yml -... +--- package: individually: true -... ``` This will switch the plugin to per function packaging which makes use of the multi-compiler @@ -540,14 +541,17 @@ if you are trying to override the entry in webpack.config.js with other unsuppor The individual packaging needs more time at the packaging phase, but you'll get that paid back twice at runtime. -#### Individual packaging concurrency +#### Individual packaging concurrency/serializdCompile + ```yaml # serverless.yml custom: webpack: concurrency: 5 + serializedCompile: true # for backward compatibility, same as concurrency: 1 ``` -Will run each webpack build one at a time which helps reduce memory usage and in some cases impoves overall build performance. + +This runs webpack builds in parallel, throttled to `concurrency`. It reduces memory usage and in some cases impoves overall build performance. ## Usage @@ -580,7 +584,7 @@ All options that are supported by invoke local can be used as usual: On CI systems it is likely that you'll run multiple integration tests with `invoke local` sequentially. To improve this, you can do one compile and run multiple invokes on the -compiled output - it is not necessary to compile again before each and every invoke. +compiled output - it is not necessary to compile again before each and every invoke. ```bash $ serverless webpack @@ -633,13 +637,13 @@ simulate AWS Lambda and AWS API Gateway locally. Add the plugins to your `serverless.yml` file and make sure that `serverless-webpack` precedes `serverless-offline` as the order is important: + ```yaml - plugins: - ... - - serverless-webpack - ... - - serverless-offline - ... +plugins: ... + - serverless-webpack + ... + - serverless-offline + ... ``` Run `serverless offline` or `serverless offline start` to start the Lambda/API simulation. @@ -666,11 +670,12 @@ you have use the `--location` option. Configure your service the same as mentioned above, but additionally add the `serverless-dynamodb-local` plugin as follows: + ```yaml - plugins: - - serverless-webpack - - serverless-dynamodb-local - - serverless-offline +plugins: + - serverless-webpack + - serverless-dynamodb-local + - serverless-offline ``` Run `serverless offline start`. @@ -717,19 +722,19 @@ plugin with Babel. To try it, from inside the example folder: Plugin commands are supported by the following providers. ⁇ indicates that command has not been tested with that provider. -| | AWS Lambda | Apache OpenWhisk | Azure Functions | Google Cloud Functions | -|-----------------------|------------|------------------|-----------------|------------------------| -| webpack | ✔︎ | ✔︎ | ⁇ | ⁇ | -| invoke local | ✔︎ | ✔︎ | ⁇ | ⁇ | -| invoke local --watch | ✔︎ | ✔︎ | ⁇ | ⁇ | +| | AWS Lambda | Apache OpenWhisk | Azure Functions | Google Cloud Functions | +| -------------------- | ---------- | ---------------- | --------------- | ---------------------- | +| webpack | ✔︎ | ✔︎ | ⁇ | ⁇ | +| invoke local | ✔︎ | ✔︎ | ⁇ | ⁇ | +| invoke local --watch | ✔︎ | ✔︎ | ⁇ | ⁇ | ## Plugin support The following serverless plugins are explicitly supported with `serverless-webpack` -| Plugin | NPM | -|-----------------------------------|-----| -| serverless-offline | [![NPM][ico-serverless-offline]][link-serverless-offline] | +| Plugin | NPM | +| --------------------------------- | ----------------------------------------------------------------- | +| serverless-offline | [![NPM][ico-serverless-offline]][link-serverless-offline] | | serverless-step-functions-offline | [![NPM][ico-step-functions-offline]][link-step-functions-offline] | ## For developers @@ -801,14 +806,12 @@ See [CHANGELOG.md](./CHANGELOG.md) [ico-build]: https://travis-ci.org/serverless-heaven/serverless-webpack.svg?branch=master [ico-coverage]: https://coveralls.io/repos/github/serverless-heaven/serverless-webpack/badge.svg?branch=master [ico-contributors]: https://img.shields.io/github/contributors/serverless-heaven/serverless-webpack.svg - [link-serverless]: https://www.serverless.com/ [link-license]: ./blob/master/LICENSE [link-npm]: https://www.npmjs.com/package/serverless-webpack [link-build]: https://travis-ci.org/serverless-heaven/serverless-webpack [link-coverage]: https://coveralls.io/github/serverless-heaven/serverless-webpack?branch=master [link-contributors]: https://github.com/serverless-heaven/serverless-webpack/graphs/contributors - [link-webpack]: https://webpack.github.io/ [link-babel]: https://babeljs.io/ [link-webpack-stats]: https://webpack.js.org/configuration/stats/ From 4ac320b9aef231412e79a713635aae3a81b34392 Mon Sep 17 00:00:00 2001 From: Vicary Date: Sun, 4 Oct 2020 21:39:33 +0800 Subject: [PATCH 25/32] fix tests --- tests/compile.test.js | 98 ++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/tests/compile.test.js b/tests/compile.test.js index f0de93576..957583a85 100644 --- a/tests/compile.test.js +++ b/tests/compile.test.js @@ -44,10 +44,13 @@ describe('compile', () => { consoleLog: sandbox.stub() }; - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); }); afterEach(() => { @@ -62,9 +65,8 @@ describe('compile', () => { it('should compile with webpack from a context configuration', () => { const testWebpackConfig = 'testconfig'; module.webpackConfig = testWebpackConfig; - return expect(module.compile()).to.be.fulfilled - .then(() => { - expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); + return expect(module.compile()).to.be.fulfilled.then(() => { + expect(webpackMock).to.have.been.calledWith(testWebpackConfig); expect(webpackMock.compilerMock.run).to.have.been.calledOnce; return null; }); @@ -78,25 +80,26 @@ describe('compile', () => { }); it('should work with multi compile', () => { - const testWebpackConfig = ['testconfig']; + const testWebpackConfig = 'testconfig'; const multiStats = { - stats: [{ - compilation: { - errors: [], - compiler: { - outputPath: 'statsMock-outputPath', + stats: [ + { + compilation: { + errors: [], + compiler: { + outputPath: 'statsMock-outputPath' + } }, - }, - toString: sandbox.stub().returns('testStats'), - hasErrors: _.constant(false) - }] + toString: sandbox.stub().returns('testStats'), + hasErrors: _.constant(false) + } + ] }; module.webpackConfig = testWebpackConfig; module.multiCompile = true; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, multiStats); - return expect(module.compile()).to.be.fulfilled - .then(() => { + return expect(module.compile()).to.be.fulfilled.then(() => { expect(webpackMock).to.have.been.calledWith(testWebpackConfig); expect(webpackMock.compilerMock.run).to.have.been.calledOnce; return null; @@ -104,30 +107,31 @@ describe('compile', () => { }); it('should work with concurrent compile', () => { - const testWebpackConfig = ['testconfig']; + const testWebpackConfig = 'testconfig'; const multiStats = { - stats: [{ - compilation: { - errors: [], - compiler: { - outputPath: 'statsMock-outputPath', + stats: [ + { + compilation: { + errors: [], + compiler: { + outputPath: 'statsMock-outputPath' + } }, - }, - toString: sandbox.stub().returns('testStats'), - hasErrors: _.constant(false) - }] + toString: sandbox.stub().returns('testStats'), + hasErrors: _.constant(false) + } + ] }; module.webpackConfig = testWebpackConfig; module.multiCompile = true; module.concurrency = 1; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, multiStats); - return expect(module.compile()).to.be.fulfilled - .then(() => { - expect(webpackMock).to.have.been.calledWith(testWebpackConfig); - expect(webpackMock.compilerMock.run).to.have.been.calledOnce; - return null; - }); + return expect(module.compile()).to.be.fulfilled.then(() => { + expect(webpackMock).to.have.been.calledWith(testWebpackConfig); + expect(webpackMock.compilerMock.run).to.have.been.calledOnce; + return null; + }); }); it('should use correct stats option', () => { @@ -148,17 +152,17 @@ describe('compile', () => { module.webpackConfig = testWebpackConfig; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, mockStats); - return (expect(module.compile()).to.be.fulfilled) - .then(() => { - expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); - expect(mockStats.toString.firstCall.args).to.eql([testWebpackConfig.stats]); - module.webpackConfig = [testWebpackConfig]; - return (expect(module.compile()).to.be.fulfilled); - }) - .then(() => { - expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); - expect(mockStats.toString.args).to.eql([ [testWebpackConfig.stats], [testWebpackConfig.stats] ]); - return null; - }); + return expect(module.compile()) + .to.be.fulfilled.then(() => { + expect(webpackMock).to.have.been.calledWith(testWebpackConfig); + expect(mockStats.toString.firstCall.args).to.eql([testWebpackConfig.stats]); + module.webpackConfig = [testWebpackConfig]; + return expect(module.compile()).to.be.fulfilled; + }) + .then(() => { + expect(webpackMock).to.have.been.calledWith(testWebpackConfig); + expect(mockStats.toString.args).to.eql([ [testWebpackConfig.stats], [testWebpackConfig.stats] ]); + return null; + }); }); }); From ba280ad6a156342a500be5a6f6064927f9cba375 Mon Sep 17 00:00:00 2001 From: coyoteecd Date: Mon, 6 Jul 2020 17:24:48 +0300 Subject: [PATCH 26/32] Option to override concurrency setting via serverless CLI --- lib/validate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validate.js b/lib/validate.js index 4908ea0d9..36d340036 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -190,7 +190,7 @@ module.exports = { // In case of individual packaging we have to create a separate config for each function if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) { this.multiCompile = true; - this.concurrency = this.configuration.concurrency; + this.concurrency = +this.options['compile-concurrency'] || this.configuration.concurrency; this.options.verbose && this.serverless.cli.log(`Using ${this.concurrency ? 'concurrent' : 'multi'}-compile (individual packaging)`); if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) { From 17c6209d2e0afd958e39b3b59602eb2eb7aa6338 Mon Sep 17 00:00:00 2001 From: coyoteecd Date: Mon, 6 Jul 2020 23:18:44 +0300 Subject: [PATCH 27/32] Remove compile-concurrency option, since the same can be achieved via serverless.yml. Left only number conversion, since CLI options are typed as string --- lib/compile.js | 2 +- lib/validate.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compile.js b/lib/compile.js index 40e6a298f..46302e4a8 100644 --- a/lib/compile.js +++ b/lib/compile.js @@ -51,7 +51,7 @@ module.exports = { const configs = ensureArray(this.webpackConfig); const logStats = getStatsLogger(configs[0].stats, this.serverless.cli.consoleLog); - const concurrency = this.concurrency === undefined ? Infinity : this.concurrency; + const concurrency = this.concurrency === undefined ? Infinity : Number(this.concurrency); return webpackConcurrentCompile(configs, logStats, concurrency) .then(stats => { diff --git a/lib/validate.js b/lib/validate.js index 36d340036..4908ea0d9 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -190,7 +190,7 @@ module.exports = { // In case of individual packaging we have to create a separate config for each function if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) { this.multiCompile = true; - this.concurrency = +this.options['compile-concurrency'] || this.configuration.concurrency; + this.concurrency = this.configuration.concurrency; this.options.verbose && this.serverless.cli.log(`Using ${this.concurrency ? 'concurrent' : 'multi'}-compile (individual packaging)`); if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) { From 92d1cd172f156e2e0774f6bbe2a550e7f3dd4229 Mon Sep 17 00:00:00 2001 From: coyoteecd Date: Wed, 14 Oct 2020 19:06:19 +0300 Subject: [PATCH 28/32] Move the parsing and default value for concurrency option in Configuration class --- lib/Configuration.js | 23 +++++++++++++++------ lib/Configuration.test.js | 42 +++++++++++++++++++++++++++++++++++---- lib/compile.js | 6 +++++- lib/validate.js | 5 +++-- tests/compile.test.js | 13 +++++++++++- 5 files changed, 75 insertions(+), 14 deletions(-) diff --git a/lib/Configuration.js b/lib/Configuration.js index ca9a523eb..adb07b86d 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -15,7 +15,7 @@ const DefaultConfig = { packagerOptions: {}, keepOutputDirectory: false, config: null, - concurrency: undefined + concurrency: Infinity }; class Configuration { @@ -38,6 +38,21 @@ class Configuration { } } + // Concurrency may be passed via CLI, e.g. + // custom: + // webpack: + // concurrency: ${opt:compile-concurrency, 7} + // In this case it is typed as a string and we have to validate it + if (this._config.concurrency !== undefined) { + this._config.concurrency = Number(this._config.concurrency); + if (isNaN(this._config.concurrency) || this._config.concurrency < 1) { + throw new Error('concurrency option must be a positive number'); + } + } else if (this._config.serializedCompile === true) { + // Backwards compatibility with serializedCompile setting + this._config.concurrency = 1; + } + // Set defaults for all missing properties _.defaults(this._config, DefaultConfig); } @@ -79,11 +94,7 @@ class Configuration { } get concurrency() { - if (this._config.concurrency !== undefined) { - return this._config.concurrency; - } else if (this._config.serializedCompile === true) { - return 1; - } + return this._config.concurrency; } toJSON() { diff --git a/lib/Configuration.test.js b/lib/Configuration.test.js index 1309fdbfd..a4b4f023d 100644 --- a/lib/Configuration.test.js +++ b/lib/Configuration.test.js @@ -20,7 +20,7 @@ describe('Configuration', () => { packagerOptions: {}, keepOutputDirectory: false, config: null, - concurrency: undefined + concurrency: Infinity }; }); @@ -70,7 +70,7 @@ describe('Configuration', () => { packagerOptions: {}, keepOutputDirectory: false, config: null, - concurrency: undefined + concurrency: Infinity }); }); }); @@ -91,7 +91,7 @@ describe('Configuration', () => { packagerOptions: {}, keepOutputDirectory: false, config: null, - concurrency: undefined + concurrency: Infinity }); }); @@ -111,8 +111,42 @@ describe('Configuration', () => { packagerOptions: {}, keepOutputDirectory: false, config: null, - concurrency: undefined + concurrency: Infinity }); }); + + it('should accept a numeric string as concurrency value', () => { + const testCustom = { + webpack: { + includeModules: { forceInclude: ['mod1'] }, + webpackConfig: 'myWebpackFile.js', + concurrency: '3' + } + }; + const config = new Configuration(testCustom); + expect(config._config.concurrency).to.equal(3); + }); + + it('should not accept an invalid string as concurrency value', () => { + const testCustom = { + webpack: { + includeModules: { forceInclude: ['mod1'] }, + webpackConfig: 'myWebpackFile.js', + concurrency: '3abc' + } + }; + expect(() => new Configuration(testCustom)).throws(); + }); + + it('should not accept a non-positive number as concurrency value', () => { + const testCustom = { + webpack: { + includeModules: { forceInclude: ['mod1'] }, + webpackConfig: 'myWebpackFile.js', + concurrency: 0 + } + }; + expect(() => new Configuration(testCustom)).throws(); + }); }); }); diff --git a/lib/compile.js b/lib/compile.js index 46302e4a8..73902ab56 100644 --- a/lib/compile.js +++ b/lib/compile.js @@ -51,7 +51,11 @@ module.exports = { const configs = ensureArray(this.webpackConfig); const logStats = getStatsLogger(configs[0].stats, this.serverless.cli.consoleLog); - const concurrency = this.concurrency === undefined ? Infinity : Number(this.concurrency); + + if (!this.configuration) { + return BbPromise.reject('Missing plugin configuration'); + } + const concurrency = this.configuration.concurrency; return webpackConcurrentCompile(configs, logStats, concurrency) .then(stats => { diff --git a/lib/validate.js b/lib/validate.js index 4908ea0d9..f16493248 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -190,8 +190,9 @@ module.exports = { // In case of individual packaging we have to create a separate config for each function if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) { this.multiCompile = true; - this.concurrency = this.configuration.concurrency; - this.options.verbose && this.serverless.cli.log(`Using ${this.concurrency ? 'concurrent' : 'multi'}-compile (individual packaging)`); + this.options.verbose && this.serverless.cli.log( + `Using ${this.configuration.concurrency !== Infinity ? 'concurrent' : 'multi'}-compile (individual packaging)` + ); if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) { return BbPromise.reject( diff --git a/tests/compile.test.js b/tests/compile.test.js index 957583a85..b9104b5b2 100644 --- a/tests/compile.test.js +++ b/tests/compile.test.js @@ -65,6 +65,7 @@ describe('compile', () => { it('should compile with webpack from a context configuration', () => { const testWebpackConfig = 'testconfig'; module.webpackConfig = testWebpackConfig; + module.configuration = { concurrency: Infinity }; return expect(module.compile()).to.be.fulfilled.then(() => { expect(webpackMock).to.have.been.calledWith(testWebpackConfig); expect(webpackMock.compilerMock.run).to.have.been.calledOnce; @@ -72,8 +73,16 @@ describe('compile', () => { }); }); + it('should fail if configuration is missing', () => { + const testWebpackConfig = 'testconfig'; + module.webpackConfig = testWebpackConfig; + module.configuration = undefined; + return expect(module.compile()).to.be.rejectedWith('Missing plugin configuration'); + }); + it('should fail if there are compilation errors', () => { module.webpackConfig = 'testconfig'; + module.configuration = { concurrency: Infinity }; // We stub errors here. It will be reset again in afterEach() sandbox.stub(webpackMock.statsMock.compilation, 'errors').value(['error']); return expect(module.compile()).to.be.rejectedWith(/compilation error/); @@ -97,6 +106,7 @@ describe('compile', () => { }; module.webpackConfig = testWebpackConfig; module.multiCompile = true; + module.configuration = { concurrency: Infinity }; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, multiStats); return expect(module.compile()).to.be.fulfilled.then(() => { @@ -124,7 +134,7 @@ describe('compile', () => { }; module.webpackConfig = testWebpackConfig; module.multiCompile = true; - module.concurrency = 1; + module.configuration = { concurrency: 1 }; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, multiStats); return expect(module.compile()).to.be.fulfilled.then(() => { @@ -150,6 +160,7 @@ describe('compile', () => { }; module.webpackConfig = testWebpackConfig; + module.configuration = { concurrency: Infinity }; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, mockStats); return expect(module.compile()) From 79d3f658cdaa4e96eadd777ef777fe373316fc56 Mon Sep 17 00:00:00 2001 From: Vicary Date: Wed, 6 Jan 2021 19:23:36 +0800 Subject: [PATCH 29/32] revert reformatting --- README.md | 243 ++++++++++++------------------------------------------ 1 file changed, 55 insertions(+), 188 deletions(-) diff --git a/README.md b/README.md index 567ccf82d..dec7e6206 100644 --- a/README.md +++ b/README.md @@ -15,25 +15,25 @@ and much more! ## Highlights -- Configuration possibilities range from zero-config to fully customizable -- Support of `serverless package`, `serverless deploy` and `serverless deploy function` -- Support of `serverless invoke local` and `serverless invoke local --watch` -- Support of `serverless run` and `serverless run --watch` -- Integrates with [`serverless-offline`][link-serverless-offline] to simulate local API Gateway endpoints -- When enabled in your service configuration, functions are packaged and compiled - individually, resulting in smaller Lambda packages that contain only the code and - dependencies needed to run the function. This allows the plugin to fully utilize - WebPack's [Tree-Shaking][link-webpack-tree] optimization. -- Webpack version 3, 4 and 5 support -- Support NPM and Yarn for packaging -- Support asynchronous webpack configuration +* Configuration possibilities range from zero-config to fully customizable +* Support of `serverless package`, `serverless deploy` and `serverless deploy function` +* Support of `serverless invoke local` and `serverless invoke local --watch` +* Support of `serverless run` and `serverless run --watch` +* Integrates with [`serverless-offline`][link-serverless-offline] to simulate local API Gateway endpoints +* When enabled in your service configuration, functions are packaged and compiled +individually, resulting in smaller Lambda packages that contain only the code and +dependencies needed to run the function. This allows the plugin to fully utilize +WebPack's [Tree-Shaking][link-webpack-tree] optimization. +* Webpack version 3, 4 and 5 support +* Support NPM and Yarn for packaging +* Support asynchronous webpack configuration ## Recent improvements and important changes for 5.x -- Support Yarn -- Support Webpack 4 and 5 -- Cleaned up configuration. You should now use a `custom.webpack` object to configure everything relevant for the plugin. The old configuration still works but will be removed in the next major release. For details see below. -- Added support for asynchronous webpack configuration +* Support Yarn +* Support Webpack 4 and 5 +* Cleaned up configuration. You should now use a `custom.webpack` object to configure everything relevant for the plugin. The old configuration still works but will be removed in the next major release. For details see below. +* Added support for asynchronous webpack configuration For the complete release notes see the end of this document. @@ -59,9 +59,9 @@ See the sections below for detailed descriptions of the settings. The defaults a ```yaml custom: webpack: - webpackConfig: 'webpack.config.js' # Name of webpack configuration file - includeModules: false # Node modules configuration for packaging - packager: 'npm' # Packager that will be used to package your external modules + webpackConfig: 'webpack.config.js' # Name of webpack configuration file + includeModules: false # Node modules configuration for packaging + packager: 'npm' # Packager that will be used to package your external modules excludeFiles: src/**/*.test.js # Provide a glob for files to ignore ``` @@ -92,7 +92,6 @@ module.exports = { Alternatively the Webpack configuration can export an asynchronous object (e.g. a promise or async function) which will be awaited by the plugin and resolves to the final configuration object. This is useful if the confguration depends on asynchronous functions, for example, defining the AccountId of the current aws user inside AWS lambda@edge which does not support defining normal process environment variables. A basic Webpack promise configuration might look like this: - ```js // Version if the local Node.js version supports async/await // webpack.config.js @@ -116,7 +115,6 @@ module.exports = (async () => { }; })(); ``` - ```js // Version with promises // webpack.config.js @@ -214,7 +212,6 @@ This allows to set properties in the webpack configuration differently depending if the lambda code is run on the local machine or deployed. A sample is to set the compile mode with Webpack 4: - ``` mode: slsw.lib.webpack.isLocal ? "development" : "production" ``` @@ -235,8 +232,8 @@ module.exports = { output: { libraryTarget: 'commonjs', path: path.resolve(__dirname, '.webpack'), - filename: '[name].js' - } + filename: '[name].js', + }, // ... }; ``` @@ -253,11 +250,12 @@ module.exports = { // ... stats: 'minimal' // ... -}; +} ``` All the stats config can be found in [webpack's documentation][link-webpack-stats] + ### Node modules / externals By default, the plugin will try to bundle all dependencies. However, you don't @@ -271,13 +269,13 @@ option in `serverless.yml`: ```js // webpack.config.js -var nodeExternals = require('webpack-node-externals'); +var nodeExternals = require('webpack-node-externals') module.exports = { // we use webpack-node-externals to excludes all node deps. // You can manually set the externals too. - externals: [nodeExternals()] -}; + externals: [nodeExternals()], +} ``` ```yaml @@ -287,6 +285,7 @@ custom: includeModules: true # enable auto-packing of external modules ``` + All modules stated in `externals` will be excluded from bundled files. If an excluded module is stated as `dependencies` in `package.json` and it is used by the webpack chunk, it will be packed into the Serverless artifact under the `node_modules` directory. @@ -301,7 +300,6 @@ custom: includeModules: packagePath: '../package.json' # relative path to custom package.json file. ``` - > Note that only relative path is supported at the moment. #### Runtime dependencies @@ -339,8 +337,8 @@ or 'yarn' and defaults to using npm when not set. # serverless.yml custom: webpack: - packager: 'yarn' # Defaults to npm - packagerOptions: {} # Optional, depending on the selected packager + packager: 'yarn' # Defaults to npm + packagerOptions: {} # Optional, depending on the selected packager ``` You should select the packager, that you use to develop your projects, because only @@ -363,8 +361,8 @@ Using yarn will switch the whole packaging pipeline to use yarn, so does it use The yarn packager supports the following `packagerOptions`: -| Option | Type | Default | Description | -| ------------- | ---- | ------- | --------------------------------------------------- | +| Option | Type | Default | Description | +|---------------|------|---------|-------------| | ignoreScripts | bool | true | Do not execute package.json hook scripts on install | ##### Common packager options @@ -441,7 +439,7 @@ If you have a project structure that uses something like `index.js` and a co-located `index.test.js` then you have likely seen an error like: `WARNING: More than one matching handlers found for index. Using index.js` -This config option allows you to exclude files that match a glob from function +This config option allows you to exlcude files that match a glob from function resolution. Just add: `excludeFiles: **/*.test.js` (with whatever glob you want to exclude). @@ -454,19 +452,6 @@ custom: This is also useful for projects that use TypeScript. -#### Exclude Files with Regular Expression - -This config option allows you to filter files that match a regex pattern before -adding to the zip file. Just add: `excludeRegex: \.ts|test|\.map` (with whatever -regex you want to exclude). - -```yaml -# serverless.yml -custom: - webpack: - excludeRegex: /\.ts|test|\.map/ -``` - #### Keep output directory after packaging You can keep the output directory (defaults to `.webpack`) from being removed @@ -518,9 +503,10 @@ service: ```yaml # serverless.yml ---- +... package: individually: true +... ``` This will switch the plugin to per function packaging which makes use of the multi-compiler @@ -584,7 +570,7 @@ All options that are supported by invoke local can be used as usual: On CI systems it is likely that you'll run multiple integration tests with `invoke local` sequentially. To improve this, you can do one compile and run multiple invokes on the -compiled output - it is not necessary to compile again before each and every invoke. +compiled output - it is not necessary to compile again before each and every invoke. ```bash $ serverless webpack @@ -637,13 +623,13 @@ simulate AWS Lambda and AWS API Gateway locally. Add the plugins to your `serverless.yml` file and make sure that `serverless-webpack` precedes `serverless-offline` as the order is important: - ```yaml -plugins: ... - - serverless-webpack - ... - - serverless-offline - ... + plugins: + ... + - serverless-webpack + ... + - serverless-offline + ... ``` Run `serverless offline` or `serverless offline start` to start the Lambda/API simulation. @@ -670,12 +656,11 @@ you have use the `--location` option. Configure your service the same as mentioned above, but additionally add the `serverless-dynamodb-local` plugin as follows: - ```yaml -plugins: - - serverless-webpack - - serverless-dynamodb-local - - serverless-offline + plugins: + - serverless-webpack + - serverless-dynamodb-local + - serverless-offline ``` Run `serverless offline start`. @@ -722,19 +707,19 @@ plugin with Babel. To try it, from inside the example folder: Plugin commands are supported by the following providers. ⁇ indicates that command has not been tested with that provider. -| | AWS Lambda | Apache OpenWhisk | Azure Functions | Google Cloud Functions | -| -------------------- | ---------- | ---------------- | --------------- | ---------------------- | -| webpack | ✔︎ | ✔︎ | ⁇ | ⁇ | -| invoke local | ✔︎ | ✔︎ | ⁇ | ⁇ | -| invoke local --watch | ✔︎ | ✔︎ | ⁇ | ⁇ | +| | AWS Lambda | Apache OpenWhisk | Azure Functions | Google Cloud Functions | +|-----------------------|------------|------------------|-----------------|------------------------| +| webpack | ✔︎ | ✔︎ | ⁇ | ⁇ | +| invoke local | ✔︎ | ✔︎ | ⁇ | ⁇ | +| invoke local --watch | ✔︎ | ✔︎ | ⁇ | ⁇ | ## Plugin support The following serverless plugins are explicitly supported with `serverless-webpack` -| Plugin | NPM | -| --------------------------------- | ----------------------------------------------------------------- | -| serverless-offline | [![NPM][ico-serverless-offline]][link-serverless-offline] | +| Plugin | NPM | +|-----------------------------------|-----| +| serverless-offline | [![NPM][ico-serverless-offline]][link-serverless-offline] | | serverless-step-functions-offline | [![NPM][ico-step-functions-offline]][link-step-functions-offline] | ## For developers @@ -806,12 +791,14 @@ See [CHANGELOG.md](./CHANGELOG.md) [ico-build]: https://travis-ci.org/serverless-heaven/serverless-webpack.svg?branch=master [ico-coverage]: https://coveralls.io/repos/github/serverless-heaven/serverless-webpack/badge.svg?branch=master [ico-contributors]: https://img.shields.io/github/contributors/serverless-heaven/serverless-webpack.svg + [link-serverless]: https://www.serverless.com/ [link-license]: ./blob/master/LICENSE [link-npm]: https://www.npmjs.com/package/serverless-webpack [link-build]: https://travis-ci.org/serverless-heaven/serverless-webpack [link-coverage]: https://coveralls.io/github/serverless-heaven/serverless-webpack?branch=master [link-contributors]: https://github.com/serverless-heaven/serverless-webpack/graphs/contributors + [link-webpack]: https://webpack.github.io/ [link-babel]: https://babeljs.io/ [link-webpack-stats]: https://webpack.js.org/configuration/stats/ @@ -826,123 +813,3 @@ See [CHANGELOG.md](./CHANGELOG.md) [link-serverless-dynamodb-local]: https://www.npmjs.com/package/serverless-dynamodb-local [link-step-functions-offline]: https://www.npmjs.com/package/serverless-step-functions-offline [ico-step-functions-offline]: https://img.shields.io/npm/v/serverless-step-functions-offline.svg - -[comment]: # (Referenced issues) - -[link-135]: https://github.com/serverless-heaven/serverless-webpack/issues/135 - -[link-83]: https://github.com/serverless-heaven/serverless-webpack/pull/83 -[link-88]: https://github.com/serverless-heaven/serverless-webpack/pull/88 -[link-127]: https://github.com/serverless-heaven/serverless-webpack/pull/127 -[link-131]: https://github.com/serverless-heaven/serverless-webpack/pull/131 -[link-132]: https://github.com/serverless-heaven/serverless-webpack/pull/132 -[link-140]: https://github.com/serverless-heaven/serverless-webpack/pull/140 -[link-141]: https://github.com/serverless-heaven/serverless-webpack/issues/141 -[link-144]: https://github.com/serverless-heaven/serverless-webpack/issues/144 - -[link-11]: https://github.com/serverless-heaven/serverless-webpack/issues/11 -[link-107]: https://github.com/serverless-heaven/serverless-webpack/issues/107 -[link-129]: https://github.com/serverless-heaven/serverless-webpack/pull/129 -[link-154]: https://github.com/serverless-heaven/serverless-webpack/issues/154 -[link-159]: https://github.com/serverless-heaven/serverless-webpack/issues/159 - -[link-158]: https://github.com/serverless-heaven/serverless-webpack/issues/158 -[link-165]: https://github.com/serverless-heaven/serverless-webpack/issues/165 - -[link-193]: https://github.com/serverless-heaven/serverless-webpack/issues/193 - -[link-116]: https://github.com/serverless-heaven/serverless-webpack/issues/116 -[link-117]: https://github.com/serverless-heaven/serverless-webpack/issues/117 -[link-120]: https://github.com/serverless-heaven/serverless-webpack/issues/120 -[link-145]: https://github.com/serverless-heaven/serverless-webpack/issues/145 -[link-151]: https://github.com/serverless-heaven/serverless-webpack/issues/151 -[link-152]: https://github.com/serverless-heaven/serverless-webpack/issues/152 -[link-173]: https://github.com/serverless-heaven/serverless-webpack/issues/173 -[link-179]: https://github.com/serverless-heaven/serverless-webpack/pull/179 -[link-185]: https://github.com/serverless-heaven/serverless-webpack/pull/185 -[link-186]: https://github.com/serverless-heaven/serverless-webpack/pull/186 - -[link-202]: https://github.com/serverless-heaven/serverless-webpack/issues/202 - -[link-215]: https://github.com/serverless-heaven/serverless-webpack/issues/215 -[link-217]: https://github.com/serverless-heaven/serverless-webpack/issues/217 -[link-221]: https://github.com/serverless-heaven/serverless-webpack/pull/221 -[link-223]: https://github.com/serverless-heaven/serverless-webpack/issues/223 -[link-227]: https://github.com/serverless-heaven/serverless-webpack/pull/227 -[link-234]: https://github.com/serverless-heaven/serverless-webpack/pull/234 - -[link-245]: https://github.com/serverless-heaven/serverless-webpack/issues/245 - -[link-251]: https://github.com/serverless-heaven/serverless-webpack/issues/251 - -[link-126]: https://github.com/serverless-heaven/serverless-webpack/issues/126 -[link-247]: https://github.com/serverless-heaven/serverless-webpack/issues/247 -[link-250]: https://github.com/serverless-heaven/serverless-webpack/issues/250 -[link-254]: https://github.com/serverless-heaven/serverless-webpack/pull/254 -[link-260]: https://github.com/serverless-heaven/serverless-webpack/issues/260 -[link-264]: https://github.com/serverless-heaven/serverless-webpack/pull/264 -[link-265]: https://github.com/serverless-heaven/serverless-webpack/pull/265 - -[link-272]: https://github.com/serverless-heaven/serverless-webpack/issues/272 -[link-278]: https://github.com/serverless-heaven/serverless-webpack/pull/278 -[link-279]: https://github.com/serverless-heaven/serverless-webpack/issues/279 -[link-276]: https://github.com/serverless-heaven/serverless-webpack/issues/276 -[link-269]: https://github.com/serverless-heaven/serverless-webpack/issues/269 - -[link-263]: https://github.com/serverless-heaven/serverless-webpack/issues/263 - -[link-286]: https://github.com/serverless-heaven/serverless-webpack/issues/286 - -[link-315]: https://github.com/serverless-heaven/serverless-webpack/issues/315 -[link-316]: https://github.com/serverless-heaven/serverless-webpack/issues/316 -[link-253]: https://github.com/serverless-heaven/serverless-webpack/issues/253 -[link-317]: https://github.com/serverless-heaven/serverless-webpack/pull/317 -[link-321]: https://github.com/serverless-heaven/serverless-webpack/pull/321 - -[link-313]: https://github.com/serverless-heaven/serverless-webpack/pull/313 -[link-326]: https://github.com/serverless-heaven/serverless-webpack/pull/326 -[link-329]: https://github.com/serverless-heaven/serverless-webpack/issues/329 - -[link-232]: https://github.com/serverless-heaven/serverless-webpack/issues/232 -[link-331]: https://github.com/serverless-heaven/serverless-webpack/issues/331 -[link-328]: https://github.com/serverless-heaven/serverless-webpack/pull/328 -[link-336]: https://github.com/serverless-heaven/serverless-webpack/pull/336 -[link-337]: https://github.com/serverless-heaven/serverless-webpack/pull/337 - -[link-275]: https://github.com/serverless-heaven/serverless-webpack/issues/275 -[link-286]: https://github.com/serverless-heaven/serverless-webpack/issues/286 -[link-341]: https://github.com/serverless-heaven/serverless-webpack/issues/341 -[link-342]: https://github.com/serverless-heaven/serverless-webpack/issues/342 -[link-343]: https://github.com/serverless-heaven/serverless-webpack/issues/343 - -[link-349]: https://github.com/serverless-heaven/serverless-webpack/issues/349 -[link-354]: https://github.com/serverless-heaven/serverless-webpack/pull/354 -[link-355]: https://github.com/serverless-heaven/serverless-webpack/pull/355 - -[link-309]: https://github.com/serverless-heaven/serverless-webpack/issues/309 -[link-365]: https://github.com/serverless-heaven/serverless-webpack/pull/365 -[link-373]: https://github.com/serverless-heaven/serverless-webpack/pull/373 - -[link-370]: https://github.com/serverless-heaven/serverless-webpack/issues/370 - -[link-379]: https://github.com/serverless-heaven/serverless-webpack/issues/379 -[link-382]: https://github.com/serverless-heaven/serverless-webpack/pull/382 -[link-384]: https://github.com/serverless-heaven/serverless-webpack/pull/384 - -[link-393]: https://github.com/serverless-heaven/serverless-webpack/issues/393 -[link-412]: https://github.com/serverless-heaven/serverless-webpack/issues/412 -[link-418]: https://github.com/serverless-heaven/serverless-webpack/issues/418 - -[link-453]: https://github.com/serverless-heaven/serverless-webpack/issues/453 -[link-467]: https://github.com/serverless-heaven/serverless-webpack/issues/467 -[link-449]: https://github.com/serverless-heaven/serverless-webpack/issues/449 -[link-465]: https://github.com/serverless-heaven/serverless-webpack/issues/465 -[link-480]: https://github.com/serverless-heaven/serverless-webpack/issues/480 -[link-429]: https://github.com/serverless-heaven/serverless-webpack/pull/429 -[link-433]: https://github.com/serverless-heaven/serverless-webpack/issues/433 -[link-471]: https://github.com/serverless-heaven/serverless-webpack/issues/471 -[link-472]: https://github.com/serverless-heaven/serverless-webpack/pull/472 - -[link-505]: https://github.com/serverless-heaven/serverless-webpack/issues/505 -[link-499]: https://github.com/serverless-heaven/serverless-webpack/issues/499 -[link-496]: https://github.com/serverless-heaven/serverless-webpack/pull/496 From a31173e8d59dd38bc833dfe54929dfa32f2acb2a Mon Sep 17 00:00:00 2001 From: Vicary Date: Wed, 6 Jan 2021 20:14:33 +0800 Subject: [PATCH 30/32] revert dropped commits in intermediate fork parent --- index.js | 10 +- index.test.js | 31 +--- lib/cleanup.js | 14 +- lib/packExternalModules.js | 4 - lib/packageModules.js | 122 ++++-------- lib/packagers/yarn.js | 2 +- lib/packagers/yarn.test.js | 4 +- lib/validate.js | 12 +- tests/cleanup.test.js | 62 ++----- tests/mocks/fs.mock.js | 1 - tests/packExternalModules.test.js | 18 -- tests/packageModules.test.js | 295 +----------------------------- tests/validate.test.js | 22 +-- tests/webpack.mock.js | 9 +- 14 files changed, 83 insertions(+), 523 deletions(-) diff --git a/index.js b/index.js index e370bbebf..326669c47 100644 --- a/index.js +++ b/index.js @@ -81,7 +81,7 @@ class ServerlessWebpack { }, package: { type: 'entrypoint', - lifecycleEvents: [ 'packExternalModules', 'packageModules', 'copyExistingArtifacts' ] + lifecycleEvents: [ 'packExternalModules', 'packageModules' ] } } } @@ -91,7 +91,7 @@ class ServerlessWebpack { 'before:package:createDeploymentArtifacts': () => BbPromise.bind(this) .then(() => this.serverless.pluginManager.spawn('webpack:validate')) - .then(() => (this.skipCompile ? BbPromise.resolve() : this.serverless.pluginManager.spawn('webpack:compile'))) + .then(() => this.serverless.pluginManager.spawn('webpack:compile')) .then(() => this.serverless.pluginManager.spawn('webpack:package')), 'after:package:createDeploymentArtifacts': () => BbPromise.bind(this).then(this.cleanup), @@ -106,6 +106,10 @@ class ServerlessWebpack { BbPromise.bind(this) .then(() => { lib.webpack.isLocal = true; + // --no-build override + if (this.options.build === false) { + this.skipCompile = true; + } return this.serverless.pluginManager.spawn('webpack:validate'); }) @@ -155,8 +159,6 @@ class ServerlessWebpack { 'webpack:package:packageModules': () => BbPromise.bind(this).then(this.packageModules), - 'webpack:package:copyExistingArtifacts': () => BbPromise.bind(this).then(this.copyExistingArtifacts), - 'before:offline:start': () => BbPromise.bind(this) .tap(() => { diff --git a/index.test.js b/index.test.js index 585e8b70a..56760dbd1 100644 --- a/index.test.js +++ b/index.test.js @@ -85,7 +85,7 @@ describe('ServerlessWebpack', () => { _.set(serverless, 'service.custom.webpack.webpackConfig', 'webpack.config.ts'); - const badDeps = function() { + const badDeps = function () { new ServerlessWebpack(serverless, {}); }; @@ -133,7 +133,6 @@ describe('ServerlessWebpack', () => { sandbox.stub(slsw, 'watch').returns(BbPromise.resolve()); sandbox.stub(slsw, 'wpwatch').returns(BbPromise.resolve()); sandbox.stub(slsw, 'packExternalModules').returns(BbPromise.resolve()); - sandbox.stub(slsw, 'copyExistingArtifacts').returns(BbPromise.resolve()); sandbox.stub(slsw, 'prepareRun').returns(BbPromise.resolve()); sandbox.stub(slsw, 'watchRun').returns(BbPromise.resolve()); sandbox.stub(slsw, 'validate').returns(BbPromise.resolve()); @@ -146,7 +145,6 @@ describe('ServerlessWebpack', () => { beforeEach(() => { ServerlessWebpack.lib.webpack.isLocal = false; - slsw.skipCompile = false; }); after(() => { @@ -171,20 +169,6 @@ describe('ServerlessWebpack', () => { return null; }); }); - - it('should skip compile if requested', () => { - slsw.skipCompile = true; - return expect(slsw.hooks['before:package:createDeploymentArtifacts']()).to.be.fulfilled.then(() => { - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledTwice; - expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly( - 'webpack:validate' - ); - expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly( - 'webpack:package' - ); - return null; - }); - }); } }, { @@ -253,7 +237,7 @@ describe('ServerlessWebpack', () => { }); it('should skip compile if requested', () => { - slsw.skipCompile = true; + slsw.options.build = false; return expect(slsw.hooks['before:invoke:local:invoke']()).to.be.fulfilled.then(() => { expect(slsw.serverless.pluginManager.spawn).to.have.been.calledOnce; expect(slsw.serverless.pluginManager.spawn).to.have.been.calledWithExactly('webpack:validate'); @@ -377,17 +361,6 @@ describe('ServerlessWebpack', () => { }); } }, - { - name: 'webpack:package:copyExistingArtifacts', - test: () => { - it('should call copyExistingArtifacts', () => { - return expect(slsw.hooks['webpack:package:copyExistingArtifacts']()).to.be.fulfilled.then(() => { - expect(slsw.copyExistingArtifacts).to.have.been.calledOnce; - return null; - }); - }); - } - }, { name: 'before:offline:start', test: () => { diff --git a/lib/cleanup.js b/lib/cleanup.js index 9664c9bb5..63bfcc796 100644 --- a/lib/cleanup.js +++ b/lib/cleanup.js @@ -1,26 +1,20 @@ 'use strict'; -const _ = require('lodash'); const BbPromise = require('bluebird'); const fse = require('fs-extra'); module.exports = { cleanup() { const webpackOutputPath = this.webpackOutputPath; - const keepOutputDirectory = this.keepOutputDirectory; - const cli = this.options.verbose ? this.serverless.cli : { log: _.noop }; + const keepOutputDirectory = this.configuration.keepOutputDirectory; if (!keepOutputDirectory) { - cli.log(`Remove ${webpackOutputPath}`); + this.options.verbose && this.serverless.cli.log(`Remove ${webpackOutputPath}`); if (this.serverless.utils.dirExistsSync(webpackOutputPath)) { - // Remove async to speed up process - fse - .remove(webpackOutputPath) - .then(() => cli.log(`Removing ${webpackOutputPath} done`)) - .catch(error => cli.log(`Error occurred while removing ${webpackOutputPath}: ${error}`)); + fse.removeSync(webpackOutputPath); } } else { - cli.log(`Keeping ${webpackOutputPath}`); + this.options.verbose && this.serverless.cli.log(`Keeping ${webpackOutputPath}`); } return BbPromise.resolve(); diff --git a/lib/packExternalModules.js b/lib/packExternalModules.js index 8ae24e6c1..cd762a304 100644 --- a/lib/packExternalModules.js +++ b/lib/packExternalModules.js @@ -228,10 +228,6 @@ module.exports = { * and performance. */ packExternalModules() { - if (this.skipCompile) { - return BbPromise.resolve(); - } - const stats = this.compileStats; const includes = this.configuration.includeModules; diff --git a/lib/packageModules.js b/lib/packageModules.js index 4d6eac5f2..422af3893 100644 --- a/lib/packageModules.js +++ b/lib/packageModules.js @@ -11,8 +11,6 @@ const semver = require('semver'); function setArtifactPath(funcName, func, artifactPath) { const version = this.serverless.getVersion(); - this.options.verbose && this.serverless.cli.log(`Setting artifact for function '${funcName}' to '${artifactPath}'`); - // Serverless changed the artifact path location in version 1.18 if (semver.lt(version, '1.18.0')) { func.artifact = artifactPath; @@ -28,23 +26,18 @@ function setArtifactPath(funcName, func, artifactPath) { function zip(directory, name) { const zip = archiver.create('zip'); // Create artifact in temp path and move it to the package path (if any) later - // This allows us to persist the webpackOutputPath and re-use the compiled output - const artifactFilePath = path.join(this.webpackOutputPath, name); + const artifactFilePath = path.join(this.serverless.config.servicePath, '.serverless', name); this.serverless.utils.writeFileDir(artifactFilePath); const output = fs.createWriteStream(artifactFilePath); - let files = glob.sync('**', { + const files = glob.sync('**', { cwd: directory, dot: true, silent: true, follow: true }); - if (this.configuration.excludeRegex) { - files = _.filter(files, f => f.match(this.configuration.excludeRegex) === null); - } - if (_.isEmpty(files)) { const error = new this.serverless.classes.Error('Packaging: No files found'); return BbPromise.reject(error); @@ -76,47 +69,13 @@ function zip(directory, name) { }); } -function getArtifactLocations(name) { - const archiveName = `${name}.zip`; - - const webpackArtifact = path.join(this.webpackOutputPath, archiveName); - const serverlessArtifact = path.join('.serverless', archiveName); - - return { webpackArtifact, serverlessArtifact }; -} - -function copyArtifactByName(artifactName) { - const { webpackArtifact, serverlessArtifact } = getArtifactLocations.call(this, artifactName); - - // Make sure the destination dir exists - this.serverless.utils.writeFileDir(serverlessArtifact); - - fs.copyFileSync(webpackArtifact, serverlessArtifact); -} - -function setServiceArtifactPath(artifactPath) { - _.set(this.serverless, 'service.package.artifact', artifactPath); -} - -function isIndividialPackaging() { - return _.get(this.serverless, 'service.package.individually'); -} - -function getArtifactName(entryFunction) { - return `${entryFunction.funcName || this.serverless.service.getServiceObject().name}.zip`; -} - module.exports = { packageModules() { - if (this.skipCompile) { - return BbPromise.resolve(); - } - const stats = this.compileStats; return BbPromise.mapSeries(stats.stats, (compileStats, index) => { const entryFunction = _.get(this.entryFunctions, index, {}); - const filename = getArtifactName.call(this, entryFunction); + const filename = `${entryFunction.funcName || this.serverless.service.getServiceObject().name}.zip`; const modulePath = compileStats.compilation.compiler.outputPath; const startZip = _.now(); @@ -128,52 +87,37 @@ module.exports = { this.serverless.cli.log( `Zip ${_.isEmpty(entryFunction) ? 'service' : 'function'}: ${modulePath} [${_.now() - startZip} ms]` ) - ); - }); - }, - - copyExistingArtifacts() { - this.serverless.cli.log('Copying existing artifacts...'); - const allFunctionNames = this.serverless.service.getAllFunctions(); - - // Copy artifacts to package location - if (isIndividialPackaging.call(this)) { - _.forEach(allFunctionNames, funcName => copyArtifactByName.call(this, funcName)); - } else { - // Copy service packaged artifact - const serviceName = this.serverless.service.getServiceObject().name; - copyArtifactByName.call(this, serviceName); - } - - _.forEach(allFunctionNames, funcName => { - const func = this.serverless.service.getFunction(funcName); - - const archiveName = isIndividialPackaging.call(this) ? funcName : this.serverless.service.getServiceObject().name; - - const { serverlessArtifact } = getArtifactLocations.call(this, archiveName); - setArtifactPath.call(this, funcName, func, serverlessArtifact); - }); - - // Set artifact locations - if (isIndividialPackaging.call(this)) { - _.forEach(allFunctionNames, funcName => { - const func = this.serverless.service.getFunction(funcName); - - const archiveName = funcName; - - const { serverlessArtifact } = getArtifactLocations.call(this, archiveName); - setArtifactPath.call(this, funcName, func, serverlessArtifact); - }); - } else { - const archiveName = this.serverless.service.getServiceObject().name; - - const { serverlessArtifact } = getArtifactLocations.call(this, archiveName); - - if (_.get(this.serverless, 'service.provider.name') === 'google') { - setServiceArtifactPath.call(this, serverlessArtifact); + ) + .then(artifactPath => { + if (_.get(this.serverless, 'service.package.individually')) { + setArtifactPath.call( + this, + entryFunction.funcName, + entryFunction.func, + path.relative(this.serverless.config.servicePath, artifactPath) + ); + } + return artifactPath; + }); + }).then(artifacts => { + if (!_.get(this.serverless, 'service.package.individually') && !_.isEmpty(artifacts)) { + // Set the service artifact to all functions + const allFunctionNames = this.serverless.service.getAllFunctions(); + _.forEach(allFunctionNames, funcName => { + const func = this.serverless.service.getFunction(funcName); + setArtifactPath.call(this, funcName, func, path.relative(this.serverless.config.servicePath, artifacts[0])); + }); + // For Google set the service artifact path + if (_.get(this.serverless, 'service.provider.name') === 'google') { + _.set( + this.serverless, + 'service.package.artifact', + path.relative(this.serverless.config.servicePath, artifacts[0]) + ); + } } - } - return BbPromise.resolve(); + return null; + }); } }; diff --git a/lib/packagers/yarn.js b/lib/packagers/yarn.js index 8895f5cbf..d1dcd74d9 100644 --- a/lib/packagers/yarn.js +++ b/lib/packagers/yarn.js @@ -117,7 +117,7 @@ class Yarn { static install(cwd, packagerOptions) { const command = /^win/.test(process.platform) ? 'yarn.cmd' : 'yarn'; - const args = [ 'install', '--pure-lockfile', '--non-interactive' ]; + const args = [ 'install', '--frozen-lockfile', '--non-interactive' ]; // Convert supported packagerOptions if (packagerOptions.ignoreScripts) { diff --git a/lib/packagers/yarn.test.js b/lib/packagers/yarn.test.js index 8ec580988..63fb47435 100644 --- a/lib/packagers/yarn.test.js +++ b/lib/packagers/yarn.test.js @@ -218,7 +218,7 @@ describe('yarn', () => { expect(Utils.spawnProcess).to.have.been.calledOnce; expect(Utils.spawnProcess).to.have.been.calledWithExactly( sinon.match(/^yarn/), - [ 'install', '--pure-lockfile', '--non-interactive' ], + [ 'install', '--frozen-lockfile', '--non-interactive' ], { cwd: 'myPath' } @@ -234,7 +234,7 @@ describe('yarn', () => { expect(Utils.spawnProcess).to.have.been.calledOnce; expect(Utils.spawnProcess).to.have.been.calledWithExactly( sinon.match(/^yarn/), - [ 'install', '--pure-lockfile', '--non-interactive', '--ignore-scripts' ], + [ 'install', '--frozen-lockfile', '--non-interactive', '--ignore-scripts' ], { cwd: 'myPath' } diff --git a/lib/validate.js b/lib/validate.js index f16493248..0659c3c05 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -172,8 +172,7 @@ module.exports = { } // Skip compilation with --no-build - if (this.options.build === false) { - this.skipCompile = true; + if (this.skipCompile) { this.serverless.cli.log('Skipping build and using existing compiled output'); if (!fse.pathExistsSync(this.webpackConfig.output.path)) { return BbPromise.reject(new this.serverless.classes.Error('No compiled output found')); @@ -190,9 +189,12 @@ module.exports = { // In case of individual packaging we have to create a separate config for each function if (_.has(this.serverless, 'service.package') && this.serverless.service.package.individually) { this.multiCompile = true; - this.options.verbose && this.serverless.cli.log( - `Using ${this.configuration.concurrency !== Infinity ? 'concurrent' : 'multi'}-compile (individual packaging)` - ); + this.options.verbose && + this.serverless.cli.log( + `Using ${ + this.configuration.concurrency !== Infinity ? 'concurrent' : 'multi' + }-compile (individual packaging)` + ); if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) { return BbPromise.reject( diff --git a/tests/cleanup.test.js b/tests/cleanup.test.js index dec18893a..4d9eda2d2 100644 --- a/tests/cleanup.test.js +++ b/tests/cleanup.test.js @@ -14,7 +14,7 @@ const expect = chai.expect; const FseMock = sandbox => ({ copy: sandbox.stub(), - remove: sandbox.stub() + removeSync: sandbox.stub() }); describe('cleanup', () => { @@ -47,7 +47,6 @@ describe('cleanup', () => { serverless = new Serverless(); serverless.cli = { log: sandbox.stub(), - error: sandbox.stub(), consoleLog: sandbox.stub() }; dirExistsSyncStub = sandbox.stub(serverless.utils, 'dirExistsSync'); @@ -55,10 +54,9 @@ describe('cleanup', () => { module = _.assign( { serverless, - options: { - verbose: true - }, - webpackOutputPath: 'my/Output/Path' + options: {}, + webpackOutputPath: 'my/Output/Path', + configuration: {} }, baseModule ); @@ -67,78 +65,42 @@ describe('cleanup', () => { afterEach(() => { // This will reset the webpackMock too sandbox.restore(); - fseMock.remove.reset(); - serverless.cli.log.reset(); }); it('should remove output dir if it exists', () => { dirExistsSyncStub.returns(true); - fseMock.remove.resolves(true); + fseMock.removeSync.reset(); return expect(module.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.have.been.calledOnce; expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path'); - expect(fseMock.remove).to.have.been.calledOnce; - expect(serverless.cli.log).to.have.been.calledWith('Removing my/Output/Path done'); + expect(fseMock.removeSync).to.have.been.calledOnce; return null; }); }); - it('should log nothing is verbose is false', () => { - dirExistsSyncStub.returns(true); - fseMock.remove.resolves(true); - - module = _.assign( - { - serverless, - options: { - verbose: false - }, - webpackOutputPath: 'my/Output/Path' - }, - baseModule - ); - - return expect(module.cleanup()).to.be.fulfilled.then(() => { - expect(dirExistsSyncStub).to.have.been.calledOnce; - expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path'); - expect(fseMock.remove).to.have.been.calledOnce; - expect(serverless.cli.log).not.to.have.been.called; - return null; - }); - }); - - it('should log an error if it occurs', () => { - dirExistsSyncStub.returns(true); - fseMock.remove.rejects('remove error'); - - return expect(module.cleanup()).to.be.fulfilled.then(() => { - expect(serverless.cli.log).to.have.been.calledWith('Error occurred while removing my/Output/Path: remove error'); - - return null; - }); - }); - - it('should not call remove if output dir does not exists', () => { + it('should not call removeSync if output dir does not exists', () => { dirExistsSyncStub.returns(false); + fseMock.removeSync.reset(); return expect(module.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.have.been.calledOnce; expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path'); - expect(fseMock.remove).to.not.have.been.called; + expect(fseMock.removeSync).to.not.have.been.called; return null; }); }); it('should keep output dir if keepOutputDir = true', () => { dirExistsSyncStub.returns(true); + fseMock.removeSync.reset(); const configuredModule = _.assign({}, module, { - keepOutputDirectory: true + configuration: { keepOutputDirectory: true } }); return expect(configuredModule.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.not.have.been.calledOnce; - expect(fseMock.remove).to.not.have.been.called; + expect(fseMock.removeSync).to.not.have.been.called; return null; }); }); diff --git a/tests/mocks/fs.mock.js b/tests/mocks/fs.mock.js index a9e06cea8..8590528a3 100644 --- a/tests/mocks/fs.mock.js +++ b/tests/mocks/fs.mock.js @@ -23,7 +23,6 @@ module.exports.create = sandbox => { readFileSync: sandbox.stub(), statSync: sinon.stub().returns(statMock), // Persistent stub writeFileSync: sandbox.stub(), - copyFileSync: sandbox.stub(), _streamMock: streamMock, _statMock: statMock diff --git a/tests/packExternalModules.test.js b/tests/packExternalModules.test.js index 236ea593b..b1abd4305 100644 --- a/tests/packExternalModules.test.js +++ b/tests/packExternalModules.test.js @@ -334,24 +334,6 @@ describe('packExternalModules', () => { ); }); - it('should do nothing if skipCompile is true', () => { - module.configuration = new Configuration({ - webpack: { - includeModules: { - packagePath: path.join('locals', 'package.json') - } - } - }); - module.skipCompile = true; - return expect(module.packExternalModules()).to.be.fulfilled.then(() => - BbPromise.all([ - expect(fsExtraMock.copy).to.not.have.been.called, - expect(packagerFactoryMock.get).to.not.have.been.called, - expect(writeFileSyncStub).to.not.have.been.called - ]) - ); - }); - it('should copy needed package sections if available', () => { const originalPackageJSON = { name: 'test-service', diff --git a/tests/packageModules.test.js b/tests/packageModules.test.js index bfd11d839..0d5665bea 100644 --- a/tests/packageModules.test.js +++ b/tests/packageModules.test.js @@ -7,7 +7,6 @@ const path = require('path'); const sinon = require('sinon'); const mockery = require('mockery'); const Serverless = require('serverless'); -const Configuration = require('../lib/Configuration'); // Mocks const fsMockFactory = require('./mocks/fs.mock'); @@ -73,9 +72,7 @@ describe('packageModules', () => { module = _.assign( { serverless, - options: {}, - webpackOutputPath: '.webpack', - configuration: new Configuration() + options: {} }, baseModule ); @@ -100,18 +97,6 @@ describe('packageModules', () => { ); }); - it('should do nothing if skipCompile is true', () => { - module.skipCompile = true; - return expect(module.packageModules()).to.be.fulfilled.then(() => - BbPromise.all([ - expect(archiverMock.create).to.not.have.been.called, - expect(writeFileDirStub).to.not.have.been.called, - expect(fsMock.createWriteStream).to.not.have.been.called, - expect(globMock.sync).to.not.have.been.called - ]) - ); - }); - describe('with service packaging', () => { beforeEach(() => { // Setup behavior for service packaging @@ -157,6 +142,8 @@ describe('packageModules', () => { fsMock._streamMock.on.withArgs('close').yields(); fsMock._statMock.isDirectory.returns(false); + const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); + module.compileStats = stats; return expect(module.packageModules()).to.be.fulfilled.then(() => BbPromise.all([ @@ -220,6 +207,8 @@ describe('packageModules', () => { fsMock._streamMock.on.withArgs('close').yields(); fsMock._statMock.isDirectory.returns(false); + const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); + module.compileStats = stats; return expect(module.packageModules()).to.be.fulfilled.then(() => expect(serverless.service).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath) @@ -264,6 +253,8 @@ describe('packageModules', () => { fsMock._streamMock.on.withArgs('close').yields(); fsMock._statMock.isDirectory.returns(false); + const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); + module.compileStats = stats; return BbPromise.each([ '1.18.1', '2.17.0', '10.15.3' ], version => { getVersionStub.returns(version); @@ -329,54 +320,6 @@ describe('packageModules', () => { module.compileStats = stats; return expect(module.packageModules()).to.be.rejectedWith('Packaging: No files found'); }); - - it('should reject if no files are found because all files are excluded using regex', () => { - module.configuration = new Configuration({ - webpack: { - excludeRegex: /.*/ - } - }); - - // Test data - const stats = { - stats: [ - { - compilation: { - compiler: { - outputPath: '/my/Service/Path/.webpack/service' - } - } - } - ] - }; - const files = [ 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' ]; - const allFunctions = [ 'func1', 'func2' ]; - const func1 = { - handler: 'src/handler1', - events: [] - }; - const func2 = { - handler: 'src/handler2', - events: [] - }; - // Serverless behavior - sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path'); - getVersionStub.returns('1.18.0'); - getServiceObjectStub.returns({ - name: 'test-service' - }); - getAllFunctionsStub.returns(allFunctions); - getFunctionStub.withArgs('func1').returns(func1); - getFunctionStub.withArgs('func2').returns(func2); - // Mock behavior - globMock.sync.returns(files); - fsMock._streamMock.on.withArgs('open').yields(); - fsMock._streamMock.on.withArgs('close').yields(); - fsMock._statMock.isDirectory.returns(false); - - module.compileStats = stats; - return expect(module.packageModules()).to.be.rejectedWith('Packaging: No files found'); - }); }); describe('with individual packaging', () => { @@ -445,232 +388,14 @@ describe('packageModules', () => { fsMock._statMock.isDirectory.returns(false); module.compileStats = stats; - - return expect(module.packageModules()).to.be.fulfilled; - }); - }); - }); - - describe('copyExistingArtifacts()', () => { - const allFunctions = [ 'func1', 'func2' ]; - const func1 = { - handler: 'src/handler1', - events: [] - }; - const func2 = { - handler: 'src/handler2', - events: [] - }; - - const entryFunctions = [ - { - handlerFile: 'src/handler1.js', - funcName: 'func1', - func: func1 - }, - { - handlerFile: 'src/handler2.js', - funcName: 'func2', - func: func2 - } - ]; - - describe('with service packaging', () => { - afterEach(() => { - fsMock.copyFileSync.resetHistory(); - }); - - beforeEach(() => { - _.set(module, 'entryFunctions', entryFunctions); - _.set(serverless.service.package, 'individually', false); - getVersionStub.returns('1.18.0'); - getServiceObjectStub.returns({ - name: 'test-service' - }); - getAllFunctionsStub.returns(allFunctions); - getFunctionStub.withArgs('func1').returns(func1); - getFunctionStub.withArgs('func2').returns(func2); - }); - - it('copies the artifact', () => { - const expectedArtifactSource = path.join('.webpack', 'test-service.zip'); - const expectedArtifactDestination = path.join('.serverless', 'test-service.zip'); - - return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => - BbPromise.all([ - // Should copy the artifact into .serverless - expect(fsMock.copyFileSync).callCount(1), - expect(fsMock.copyFileSync).to.be.calledWith(expectedArtifactSource, expectedArtifactDestination), - - // Should set package artifact for each function to the single artifact - expect(func1) - .to.have.a.nested.property('package.artifact') - .that.equals(expectedArtifactDestination), - expect(func2) - .to.have.a.nested.property('package.artifact') - .that.equals(expectedArtifactDestination) - ]) - ); - }); - - it('should set the function artifact depending on the serverless version', () => { - // Test data - const stats = { - stats: [ - { - compilation: { - compiler: { - outputPath: '/my/Service/Path/.webpack/service' - } - } - } - ] - }; - const files = [ 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' ]; - const allFunctions = [ 'func1', 'func2' ]; - const func1 = { - handler: 'src/handler1', - events: [] - }; - const func2 = { - handler: 'src/handler2', - events: [] - }; - // Serverless behavior - sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path'); - getServiceObjectStub.returns({ - name: 'test-service' - }); - getAllFunctionsStub.returns(allFunctions); - getFunctionStub.withArgs('func1').returns(func1); - getFunctionStub.withArgs('func2').returns(func2); - // Mock behavior - globMock.sync.returns(files); - fsMock._streamMock.on.withArgs('open').yields(); - fsMock._streamMock.on.withArgs('close').yields(); - fsMock._statMock.isDirectory.returns(false); - - const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); - - module.compileStats = stats; - return BbPromise.each([ '1.18.1', '2.17.0', '10.15.3' ], version => { - getVersionStub.returns(version); - return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => - BbPromise.all([ - expect(func1) - .to.have.a.nested.property('package.artifact') - .that.equals(expectedArtifactPath), - expect(func2) - .to.have.a.nested.property('package.artifact') - .that.equals(expectedArtifactPath) - ]) - ); - }).then(() => - BbPromise.each([ '1.17.0', '1.16.0-alpha', '1.15.3' ], version => { - getVersionStub.returns(version); - return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => - BbPromise.all([ - expect(func1) - .to.have.a.nested.property('artifact') - .that.equals(expectedArtifactPath), - expect(func2) - .to.have.a.nested.property('artifact') - .that.equals(expectedArtifactPath), - expect(func1).to.have.a.nested.property('package.disable').that.is.true, - expect(func2).to.have.a.nested.property('package.disable').that.is.true - ]) - ); - }) - ); - }); - - describe('with the Google provider', () => { - let oldProviderName; - - beforeEach(() => { - oldProviderName = serverless.service.provider.name; - // Imitate Google provider - serverless.service.provider.name = 'google'; - }); - - afterEach(() => { - if (oldProviderName) { - serverless.service.provider.name = oldProviderName; - } else { - _.unset(serverless.service.provider, 'name'); - } - }); - - it('should set the service artifact path', () => { - // Test data - const allFunctions = [ 'func1', 'func2' ]; - const func1 = { - handler: 'handler1', - events: [] - }; - const func2 = { - handler: 'handler2', - events: [] - }; - sandbox.stub(serverless.config, 'servicePath').value('/my/Service/Path'); - getVersionStub.returns('1.18.0'); - getServiceObjectStub.returns({ - name: 'test-service' - }); - getAllFunctionsStub.returns(allFunctions); - getFunctionStub.withArgs('func1').returns(func1); - getFunctionStub.withArgs('func2').returns(func2); - // Mock behavior - // fsMock._streamMock.on.withArgs('open').yields(); - // fsMock._streamMock.on.withArgs('close').yields(); - // fsMock._statMock.isDirectory.returns(false); - - const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); - - return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => - expect(serverless.service) - .to.have.a.nested.property('package.artifact') - .that.equals(expectedArtifactPath) - ); - }); - }); - }); - - describe('with individual packaging', () => { - afterEach(() => { - fsMock.copyFileSync.resetHistory(); - }); - - beforeEach(() => { - _.set(module, 'entryFunctions', entryFunctions); - _.set(serverless.service.package, 'individually', true); - getVersionStub.returns('1.18.0'); - getServiceObjectStub.returns({ - name: 'test-service' - }); - getAllFunctionsStub.returns(allFunctions); - getFunctionStub.withArgs('func1').returns(func1); - getFunctionStub.withArgs('func2').returns(func2); - }); - - it('copies each artifact', () => { - const expectedFunc1Destination = path.join('.serverless', 'func1.zip'); - const expectedFunc2Destination = path.join('.serverless', 'func2.zip'); - - return expect(module.copyExistingArtifacts()).to.be.fulfilled.then(() => + return expect(module.packageModules()).to.be.fulfilled.then(() => BbPromise.all([ - // Should copy an artifact per function into .serverless - expect(fsMock.copyFileSync).callCount(2), - expect(fsMock.copyFileSync).to.be.calledWith(path.join('.webpack', 'func1.zip'), expectedFunc1Destination), - expect(fsMock.copyFileSync).to.be.calledWith(path.join('.webpack', 'func2.zip'), expectedFunc2Destination), - - // Should set package artifact locations expect(func1) .to.have.a.nested.property('package.artifact') - .that.equals(expectedFunc1Destination), + .that.equals(path.join('.serverless', 'func1.zip')), expect(func2) .to.have.a.nested.property('package.artifact') - .that.equals(expectedFunc2Destination) + .that.equals(path.join('.serverless', 'func2.zip')) ]) ); }); diff --git a/tests/validate.test.js b/tests/validate.test.js index 24c513aa9..12c2ae89a 100644 --- a/tests/validate.test.js +++ b/tests/validate.test.js @@ -960,24 +960,6 @@ describe('validate', () => { }); describe('with skipped builds', () => { - it('should set `skipComile` to true if `options.build` is false', () => { - const testConfig = { - entry: 'test', - output: {} - }; - const testServicePath = 'testpath'; - module.serverless.config.servicePath = testServicePath; - _.set(module.serverless.service, 'custom.webpack.config', testConfig); - - module.options.build = false; - - fsExtraMock.pathExistsSync.returns(true); - return module.validate().then(() => { - expect(module.skipCompile).to.be.true; - return null; - }); - }); - it('should keep output directory', () => { const testConfig = { entry: 'test', @@ -986,7 +968,7 @@ describe('validate', () => { const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - module.options.build = false; + module.skipCompile = true; fsExtraMock.pathExistsSync.returns(true); return module.validate().then(() => { expect(module.keepOutputDirectory).to.be.true; @@ -1002,7 +984,7 @@ describe('validate', () => { const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - module.options.build = false; + module.skipCompile = true; fsExtraMock.pathExistsSync.returns(false); return expect(module.validate()).to.be.rejectedWith(/No compiled output found/); }); diff --git a/tests/webpack.mock.js b/tests/webpack.mock.js index 5bf7194c2..23e26518f 100644 --- a/tests/webpack.mock.js +++ b/tests/webpack.mock.js @@ -6,16 +6,15 @@ const StatsMock = () => ({ compilation: { errors: [], compiler: { - outputPath: 'statsMock-outputPath', - }, + outputPath: 'statsMock-outputPath' + } }, toString: sinon.stub().returns('testStats'), hasErrors() { return Boolean(this.compilation.errors.length); - }, + } }); - const CompilerMock = (sandbox, statsMock) => ({ run: sandbox.stub().yields(null, statsMock), watch: sandbox.stub().yields(null, statsMock), @@ -23,7 +22,7 @@ const CompilerMock = (sandbox, statsMock) => ({ beforeCompile: { tapPromise: sandbox.stub() } - }, + } }); const webpackMock = sandbox => { From b8ffa34905b7164a501023426dd7e2cfbb3229ab Mon Sep 17 00:00:00 2001 From: Vicary Date: Wed, 6 Jan 2021 20:28:52 +0800 Subject: [PATCH 31/32] Remove dropped configurations --- lib/Configuration.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/Configuration.js b/lib/Configuration.js index adb07b86d..48941e4e2 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -69,10 +69,6 @@ class Configuration { return this._config.excludeFiles; } - get excludeRegex() { - return this._config.excludeRegex; - } - get packager() { return this._config.packager; } From b84a6f8f05c1eb7f94e01b5652d045ac56d4dbdb Mon Sep 17 00:00:00 2001 From: Vicary Date: Wed, 6 Jan 2021 20:36:50 +0800 Subject: [PATCH 32/32] Revert lock file to upstream master --- package-lock.json | 135 ++++++++++++++++++---------------------------- 1 file changed, 53 insertions(+), 82 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2a92be57d..76fa462c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -894,8 +894,8 @@ "chalk": "^2.4.1", "https-proxy-agent": "^4.0.0", "is-docker": "^1.1.0", + "isomorphic-fetch": "^2.2.1", "jwt-decode": "^2.2.0", - "node-fetch": "^2.6.1", "opn": "^5.5.0", "querystring": "^0.2.0", "ramda": "^0.25.0", @@ -975,9 +975,9 @@ } }, "@serverless/utils-china": { - "version": "0.1.28", - "resolved": "https://registry.npmjs.org/@serverless/utils-china/-/utils-china-0.1.28.tgz", - "integrity": "sha512-nxMBES1wR+U1U8UWaWd7CwKmoY18SRHT6h39ux8YGXgxeRd9pqKB4/TTLX4hHYMsqHteXufpFZQIhl0aGf9oww==", + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/@serverless/utils-china/-/utils-china-0.1.27.tgz", + "integrity": "sha512-ZQDTtmFBD2xl23YFFMVOTmqsgqtcxk9WKBGdixZ3ZY2MxAjrNJvBE0vPCRsYrQCs0I+TzdPDRIPSrOUJh7cpiw==", "dev": true, "requires": { "@tencent-sdk/capi": "^0.2.17", @@ -1010,9 +1010,9 @@ "dev": true }, "@sinonjs/commons": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", - "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -1152,18 +1152,18 @@ "integrity": "sha512-aYNbO+FZ/3KGeQCEkNhHFRIzBOUgc7QvcVNKXbfnhDkSfwUv91JsQQa10rDgKSTSLkXZ1UIyPe4FJJNVgw1xWQ==", "dev": true }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, "@types/object-assign": { "version": "4.0.30", "resolved": "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz", "integrity": "sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI=", "dev": true }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, "@types/request": { "version": "2.48.5", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", @@ -2865,9 +2865,9 @@ } }, "dayjs": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.9.1.tgz", - "integrity": "sha512-01NCTBg8cuMJG1OQc6PR7T66+AFYiPwgDvdJmvJBn29NGzIG+DIFxPLNjHzwz3cpFIvG+NcwIjP9hSaPVoOaDg==", + "version": "1.8.35", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.35.tgz", + "integrity": "sha512-isAbIEenO4ilm6f8cpqvgjZCsuerDAz2Kb7ri201AiNn58aqXuaLJEnCtfIMdCvERZHNGRY5lDMTr/jdAnKSWQ==", "dev": true }, "debug": { @@ -3583,20 +3583,20 @@ }, "dependencies": { "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", + "object.assign": "^4.1.0", "string.prototype.trimend": "^1.0.1", "string.prototype.trimstart": "^1.0.1" } @@ -3619,9 +3619,9 @@ "dev": true }, "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", "dev": true }, "is-regex": { @@ -3638,40 +3638,6 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true - }, - "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } - } } } }, @@ -6043,9 +6009,9 @@ } }, "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", "dev": true }, "is-builtin-module": { @@ -10690,9 +10656,9 @@ "dev": true }, "string-argv": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.0.tgz", - "integrity": "sha512-NGZHq3nkSXVtGZXTBjFru3MNfoZyIzN25T7BmvdgnSC0LCJczAGLLMQLyjywSIaAoqSemgLzBRHOsnrHbt60+Q==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", "dev": true }, "string-width": { @@ -10716,20 +10682,20 @@ }, "dependencies": { "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", + "object.assign": "^4.1.0", "string.prototype.trimend": "^1.0.1", "string.prototype.trimstart": "^1.0.1" } @@ -10954,16 +10920,10 @@ "has-flag": "^3.0.0" } }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true - }, "table": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.4.tgz", - "integrity": "sha512-IIfEAUx5QlODLblLrGTTLJA7Tk0iLSGBvgY8essPRVNGHAzThujww1YqHLs6h3HfTg55h++RzLHH5Xw/rfv+mg==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -10978,6 +10938,17 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",