Skip to content

Commit

Permalink
Updated to public release of webpack 5
Browse files Browse the repository at this point in the history
- Removed `OptimizeCSSAssetsPlugin` due to no webpack 5 support
- Fixed webpack modules resolver for projects using Yarn workspaces
- Set the default target for `browserslist` and `web`
- Fixed `getIfUtilsInstance` incorrectly caching itself which cause dev and prod builds to cross over
- Removed `entry` from `WebpackIgnoredProps` due to the new import structure available which allows more control over build outcomes
- Updated runtime tests
  • Loading branch information
cshawaus committed Oct 11, 2020
1 parent 9b9d610 commit 8d30336
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 198 deletions.
33 changes: 16 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,10 @@
"@types/jest": "^26.0.14",
"@types/lodash": "^4.14.161",
"@types/mini-css-extract-plugin": "^0.9.1",
"@types/node": "^14.11.7",
"@types/optimize-css-assets-webpack-plugin": "^5.0.1",
"@types/node": "^14.11.8",
"@types/rimraf": "^3.0.0",
"@types/sass": "^1.16.0",
"@types/stylelint-webpack-plugin": "^2.1.0",
"@types/terser-webpack-plugin": "^4.2.0",
"@types/webpack": "^4.41.22",
"@types/webpack-bundle-analyzer": "^3.8.0",
"@types/webpack-config-utils": "^2.3.1",
"@types/webpack-dev-server": "^3.11.0",
Expand All @@ -109,34 +106,33 @@
"chalk": "^4.1.0",
"child_process": "^1.0.2",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^6.2.0",
"copy-webpack-plugin": "^6.2.1",
"css-loader": "^4.3.0",
"cssnano": "^4.1.10",
"eslint-loader": "^4.0.2",
"eslint-plugin-jest": "^24.1.0",
"eslint-webpack-plugin": "^2.1.0",
"exports-loader": "^1.1.0",
"exports-loader": "^1.1.1",
"extract-loader": "^5.1.0",
"figlet": "^1.5.0",
"file-loader": "^6.1.0",
"file-loader": "^6.1.1",
"imports-loader": "^1.2.0",
"jest": "^26.5.2",
"jest-fetch-mock": "^3.0.3",
"jest-mock-console": "^1.0.1",
"jest-mock-process": "^1.4.0",
"lodash": "^4.17.20",
"mini-css-extract-plugin": "^0.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^4.0.3",
"mini-css-extract-plugin": "^1.0.0",
"postcss-loader": "^4.0.4",
"rimraf": "^3.0.2",
"sass": "^1.27.0",
"sass-loader": "^10.0.2",
"style-loader": "^1.3.0",
"sass-loader": "^10.0.3",
"style-loader": "^2.0.0",
"stylelint": "^13.7.2",
"stylelint-webpack-plugin": "^2.1.0",
"terser-webpack-plugin": "^4.2.3",
"ts-jest": "^26.4.1",
"webpack": "5.0.0-rc.4",
"webpack": "5.0.0",
"webpack-bundle-analyzer": "^3.9.0",
"webpack-config-utils": "^2.3.1",
"webpack-dev-server": "^3.11.0",
Expand All @@ -153,18 +149,21 @@
"@typescript-eslint/eslint-plugin": "^4.4.0",
"@typescript-eslint/parser": "^4.4.0",
"cross-env": "^7.0.2",
"eslint": "^7.10.0",
"eslint": "^7.11.0",
"eslint-plugin-import": "^2.22.1",
"husky": "^4.3.0",
"memfs": "^3.2.0",
"mock-fs": "^4.13.0",
"ts-node": "^9.0.0",
"ttypescript": "^1.5.12",
"typescript": "^4.0.3",
"typescript-transform-paths": "^2.0.1"
},
"peerDependencies": {
"eslint": "*",
"stylelint": "*",
"webpack": "*"
"@babel/core": "^7.11.0",
"eslint": "^7.0.0",
"postcss": "^7.0.0 || ^8.0.1",
"stylelint": "^13.0.0",
"webpack": "^5.0.0"
}
}
2 changes: 0 additions & 2 deletions src/bin/cli-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@ executeHook(Hook.COMPILER_READY, HookType.AFTER, args)

if (args.watch) {
const devServer = new WebpackDevServer(
// TODO: Remove this when fixed
// @ts-expect-error it appears 'webpack-dev-server' and the 'webpack' @types are no compatible at this time. Check again soon!
webpackInstance,
createConfig(webpackConfiguration, {
...args,
Expand Down
3 changes: 2 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export const mergeStrategy: { [key: string]: CustomizeRule } = {
'devServer.proxy' : CustomizeRule.Prepend,
'module.rules' : CustomizeRule.Append,
'plugins' : CustomizeRule.Append,
'target' : CustomizeRule.Replace,
}

/**
Expand Down Expand Up @@ -177,7 +178,7 @@ export function setupEnvironment(env: WebpackParserOptions, flags: CommandLineFl

eslint : flags.eslint ?? (env.eslint || false),
hmr : env.watch === true,
mode : env.dev === true ? 'development' : 'production',
mode : env.prod === true ? 'production' : 'development',
project : env.project as string,
stylelint : flags.stylelint ?? (env.stylelint || false),
} as Environment
Expand Down
10 changes: 5 additions & 5 deletions src/plugins/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ import ComposeMessages from '@/plugins/messages'
export default (paths: RuntimePaths): webpack.WebpackPluginInstance[] => {
const cssExtractPath = paths.out as string || 'clientlibs-header/css'

// TODO: Remove this when fixed
// @ts-expect-error some plugins haven't been updated with webpack 5 defintions so their exports are mismatched
return removeEmpty<webpack.WebpackPluginInstance>([
return removeEmpty([

getIfUtilsInstance().ifNotWatch(new ComposeMessages()),
getIfUtilsInstance().ifNotMaven(new webpack.ProgressPlugin({})),
getIfUtilsInstance().ifNotMaven(new webpack.ProgressPlugin({
percentBy: 'entries',
})),

/**
* Copies static assets from our source folder into the public structure for AEM.
Expand Down Expand Up @@ -120,5 +120,5 @@ export default (paths: RuntimePaths): webpack.WebpackPluginInstance[] => {
openAnalyzer: false,
})),

])
]) as webpack.WebpackPluginInstance[]
}
137 changes: 100 additions & 37 deletions src/runtime.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path'
import mockConsole, { RestoreConsole } from 'jest-mock-console'
import mockFS from 'mock-fs'
import { mockProcessExit } from 'jest-mock-process'
import { createFsFromVolume, IFs, Volume } from 'memfs'
import webpack from 'webpack'

Expand Down Expand Up @@ -35,12 +36,17 @@ describe('runtime', () => {
},
})

let memoryFileSystem: IFs
let restoreConsoleMock: RestoreConsole

beforeAll(() => {
const mockedFileSystem = {
// aemdesign/compose-webpack package.json
// .browserslistrc
[resolve('.browserslistrc')]: JSON.stringify(['defaults']),

// src/runtime.ts
// [resolve('src/runtime.ts')]: 'webpack caching',

// @aemdesign/compose-webpack package.json
[resolve('node_modules/@aem-design/compose-webpack/package.json')]: JSON.stringify({
version: '0.0.0-mock.0'
}),
Expand All @@ -65,7 +71,6 @@ describe('runtime', () => {
})

beforeEach(() => {
memoryFileSystem = createFsFromVolume(new Volume)
restoreConsoleMock = mockConsole()
})

Expand Down Expand Up @@ -129,60 +134,118 @@ describe('runtime', () => {
project : 'mock',
})

expect(config.mode).toStrictEqual('production')

expect(config.output.chunkFilename).toContain('[contenthash:8]')
})

test('can compile es6 javascript entry', async (done) => {
const config = configuration(composeConfiguration({
standard: {
projects: {
'mock': {
entryFile : 'basic-es6.js',
outputName : 'mock',
describe('webpack compile', () => {
test('can compile es6 javascript entry', async (done) => {
const memoryFileSystem = createFsFromVolume(new Volume)
const mockExit = mockProcessExit()

const config = configuration(composeConfiguration({
standard: {
projects: {
'mock': {
entryFile : 'basic-es6.js',
outputName : 'mock',
},
},
},
},
}), { project: 'mock' })

const compiler = webpack(config)
webpack: {
target: ['browserslist'],
},
}), { project: 'mock' })

// @ts-expect-error known that the webpack type and 'memory-fs' aren't compatible
compiler.outputFileSystem = memoryFileSystem
const compiler = webpack(config)

const stats = await compile(compiler)
// @ts-expect-error known that the webpack type and 'memfs' aren't compatible
compiler.outputFileSystem = memoryFileSystem

expect(stats.hasErrors()).toBe(false)
const stats = await compile(compiler)

const fileSystemOutput = memoryFileSystem.readdirSync('public/mock/clientlibs-footer/js')
expect(mockExit).toHaveBeenCalledTimes(0)

expect(fileSystemOutput).toHaveLength(1)
expect(fileSystemOutput).toStrictEqual(['mock.js'])
expect(stats.hasErrors()).toBe(false)

done()
})
const fileSystemOutput = memoryFileSystem.readdirSync('public/mock/clientlibs-footer/js')

test('error is thrown when disallowed webpack prop is set', () => {
const config = () => configuration({
...standardComposeConfiguration,
expect(memoryFileSystem.readFileSync('public/mock/clientlibs-footer/js/mock.js').toString())
.toContain("const foo = 'bar';\\nconsole.log(foo);")

webpack: {
// @ts-expect-error used to prove disallowed webpack props throw an error
entry: 'foo',
},
}, { project: 'mock' })
expect(fileSystemOutput).toHaveLength(1)
expect(fileSystemOutput).toStrictEqual(['mock.js'])

done()
})

test('can compile es6 javascript entry for production', async (done) => {
const memoryFileSystem = createFsFromVolume(new Volume)
const mockExit = mockProcessExit()

const config = configuration(composeConfiguration({
standard: {
projects: {
'mock': {
entryFile : 'basic-es6.js',
outputName : 'mock',
},
},
},

webpack: {
target: ['browserslist'],
},
}), {
dev : false,
prod : true,
project : 'mock',
})

expect(config).toThrowError('Forbidden webpack property detected (entry)')
const compiler = webpack(config)

// @ts-expect-error known that the webpack type and 'memfs' aren't compatible
compiler.outputFileSystem = memoryFileSystem

const stats = await compile(compiler)

expect(mockExit).toHaveBeenCalledTimes(0)

expect(stats.hasErrors()).toBe(false)

expect(memoryFileSystem.readFileSync('public/mock/clientlibs-footer/js/mock.js').toString())
.toStrictEqual('(()=>{const e=new Set;e.add("foo"),document.querySelector("body").classList.add("bar"),document.querySelector("body").innerHTML="Bar size: "+e.size})();')

done()
})
})

test('error is thrown when pom configuration is invalid', () => {
setConfiguration(ConfigurationType.MAVEN_PROJECT, resolve('pom.invalid.xml'))
describe('error handling', () => {
test('error is thrown when disallowed webpack prop is set', () => {
const config = () => configuration({
...standardComposeConfiguration,

const config = () => configuration(standardComposeConfiguration, {
project: 'mock',
webpack: {
// @ts-expect-error used to prove disallowed webpack props throw an error
devtool: 'foo',
},
}, { project: 'mock' })

expect(config).toThrowError('Forbidden webpack property detected (devtool)')
})

expect(config)
.toThrowError('Unable to continue due to missing or invalid Maven configuration values!')
test('error is thrown when pom configuration is invalid', () => {
setConfiguration(ConfigurationType.MAVEN_PROJECT, resolve('pom.invalid.xml'))

const config = () => configuration(standardComposeConfiguration, {
project: 'mock',
})

expect(config)
.toThrowError('Unable to continue due to missing or invalid Maven configuration values!')
})
})

afterEach(() => {
Expand Down
28 changes: 7 additions & 21 deletions src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from 'webpack-merge'

import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'
import TerserPlugin from 'terser-webpack-plugin'

import { logger } from '@aem-design/compose-support'
Expand Down Expand Up @@ -249,10 +248,11 @@ export default (
customizeArray : customizeArray(mergeStrategy),
customizeObject : customizeObject(mergeStrategy),
})({
context: paths.src,
devtool: getIfUtilsInstance().ifDev(flagHMR ? 'cheap-module-source-map' : 'eval-cheap-module-source-map'),
context : paths.src,
devtool : getIfUtilsInstance().ifDev(flagHMR ? 'cheap-module-source-map' : 'eval-cheap-module-source-map'),
entry,
mode,
target : ['browserslist', 'web'],

output: {
chunkFilename : `${paths.out as string || 'clientlibs-footer'}/resources/chunks/[name]${flagProd ? '.[contenthash:8]' : ''}.js`,
Expand All @@ -262,7 +262,7 @@ export default (
},

performance: {
assetFilter : (assetFilename) => !new RegExp(getConfigurable('assetFilters').join('|')).test(assetFilename),
assetFilter : (assetFilename: string) => !new RegExp(getConfigurable('assetFilters').join('|')).test(assetFilename),
hints : getIfUtilsInstance().ifDev(false, 'warning'),
maxAssetSize : 300000,
maxEntrypointSize : 300000,
Expand Down Expand Up @@ -311,10 +311,10 @@ export default (
},

optimization: {
moduleIds: 'deterministic',
chunkIds : 'deterministic',
moduleIds : 'deterministic',

minimizer: [
// TODO: Remove this when fixed
// @ts-expect-error 'webpack-dev-server' incorrectly taking over the exported 'Plugin' type
new TerserPlugin({
cache : true,
Expand All @@ -336,21 +336,6 @@ export default (
},
},
}),

// TODO: Remove this when fixed
// @ts-expect-error 'webpack-dev-server' incorrectly taking over the exported 'Plugin' type
new OptimizeCSSAssetsPlugin({
canPrint : true,
cssProcessor : require('cssnano'),

cssProcessorPluginOptions: {
preset: ['default', {
discardComments: {
removeAll: true,
},
}],
},
}),
],

splitChunks: {
Expand All @@ -370,6 +355,7 @@ export default (
// dependencies which aren't anything to do with our script.
modules: [
relative(__dirname, resolve(process.cwd(), 'node_modules')),
relative(__dirname, resolve(process.cwd(), '../node_modules')), // Useful for Yarn workspaces
'node_modules',
],
},
Expand Down
Loading

0 comments on commit 8d30336

Please sign in to comment.