Skip to content

Commit

Permalink
feat(general): split entries by configurations in stats
Browse files Browse the repository at this point in the history
Fix path and options in InjectManifestPlugin when context is set and add another test. Disable ESLint warning when devDependencies are bundled and add @babel/core which now needs to be listed explicitly. Windows path fix in HTML output. release-npm
  • Loading branch information
tobua committed Jul 17, 2023
1 parent d6aa089 commit 7dbca48
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 45 deletions.
13 changes: 13 additions & 0 deletions configuration/eslint.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ const customRules = {
'react/react-in-jsx-scope': 0,
// Allow assignment to function param properties, like parameter.innerHTML = ...
'no-param-reassign': [2, { props: false }],
// No warning when devDependencies are imported, as they are usually bundled and dependencies used to serve the bundle later.
// import/no-unresolved errors if a dependency is used that's not installed.
// This still errors if an unlisted dependency is imported.
'import/no-extraneous-dependencies': [
'error',
{
// NOTE docs seem to get the defaults wrong
// https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md
devDependencies: true,
optionalDependencies: true,
peerDependencies: true,
},
],
}

const customSettings = {
Expand Down
29 changes: 17 additions & 12 deletions configuration/rspack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,27 @@ const root = (folder: string) => resolve(process.cwd(), folder)

const getPlugins = (development: boolean) => {
const plugins: Plugins = []
const pluginOptions = options()

if (!development && options().typescript) {
if (!development && pluginOptions.typescript) {
plugins.push(new TypeScriptWebpackPlugin() as unknown as RspackPluginInstance)
}

const serviceWorkerFileName = `service-worker.${options().typescript ? 'ts' : 'js'}`
const serviceWorkerSourcePath = join(getProjectBasePath(), serviceWorkerFileName)

if (existsSync(serviceWorkerSourcePath) && !development && options().injectManifest) {
plugins.push(
new InjectManifestPlugin({
file: serviceWorkerFileName,
removeHash: true,
...options().injectManifest,
})
)
if (!development && pluginOptions.injectManifest) {
const serviceWorkerFileName =
pluginOptions.injectManifest.file ??
`./service-worker.${pluginOptions.typescript ? 'ts' : 'js'}`
const serviceWorkerSourcePath = join(getProjectBasePath(), serviceWorkerFileName)

if (existsSync(serviceWorkerSourcePath)) {
plugins.push(
new InjectManifestPlugin({
file: serviceWorkerFileName,
removeHash: true,
...pluginOptions.injectManifest,
})
)
}
}

return plugins
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
}
},
"dependencies": {
"@babel/core": "^7.22.9",
"@babel/eslint-parser": "^7.22.9",
"@babel/preset-env": "^7.22.9",
"@babel/preset-react": "^7.22.5",
Expand Down Expand Up @@ -60,7 +61,7 @@
"fork-ts-checker-webpack-plugin": "^8.0.0",
"get-port": "^7.0.0",
"global-dirs": "^3.0.1",
"inject-manifest-plugin": "^0.3.1",
"inject-manifest-plugin": "^0.3.3",
"lodash.isplainobject": "^4.0.6",
"logua": "^2.3.0",
"node-html-parser": "^6.1.5",
Expand All @@ -71,7 +72,7 @@
"postcss-styled": "^0.34.0",
"postcss-syntax": "^0.36.2",
"prettier": "^3.0.0",
"pretty-bytes": "^6.1.0",
"pretty-bytes": "^6.1.1",
"pretty-ms": "^8.0.0",
"prompts": "^2.4.2",
"serve-handler": "^6.1.5",
Expand Down
24 changes: 23 additions & 1 deletion schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,29 @@
},
"injectManifest": {
"description": "Configuration added to inject-manifest-plugin.",
"type": "object"
"type": "object",
"properties": {
"file": {
"description": "The filename pointing to the service worker.",
"type": "string"
},
"injectionPoint": {
"description": "The variable in the service worker to replace with the manifest during the build.",
"type": "string"
},
"exclude": {
"description": "List of globs for files that should be excluded from the manifest.",
"type": "array"
},
"removeHash": {
"description": "Removes hash in the emitted filename of the service worker.",
"type": "boolean"
},
"chunkName": {
"description": "The name of the service worker chunk.",
"type": "string"
}
}
},
"serve": {
"description": "Configuration passed to serve-handler package in serve script.",
Expand Down
2 changes: 1 addition & 1 deletion script/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default async (development: boolean) => {
process.exit(1)
}

logStats(stats, development, compiler)
logStats(stats, development)

done(compiler)
})
Expand Down
2 changes: 1 addition & 1 deletion script/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default async (options: Configuration = {}, inputs = {}) => {
compiler.hooks.invalid.tap('invalid', recompiling)

compiler.hooks.done.tap('done', (stats) => {
logStats(stats, true, compiler)
logStats(stats, true)
})

let server: RspackDevServer
Expand Down
2 changes: 1 addition & 1 deletion script/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default async (development = true) => {
log('Compilation failed during watch', 'error')
}

logStats(stats, development, compiler)
logStats(stats, development)
})

return {
Expand Down
25 changes: 24 additions & 1 deletion test/build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ test('Favicon can be customized.', async () => {
const htmlContents = readFile(join(dist, 'index.html'))
const imageFiles = listFilesMatching('**/*.png', '.')

expect(htmlContents).toContain(`<link rel=icon href=nested${sep}hello.png>`)
expect(htmlContents).toContain(`<link rel=icon href=nested/hello.png>`)
expect(imageFiles).toContain('dist/nested/hello.png')
})

Expand Down Expand Up @@ -484,6 +484,29 @@ test('Inject manifest plugin can be disabled.', async () => {
expect(contents[0].contents).toContain('self.INJECT_MANIFEST_PLUGIN')
})

test('Service Worker entry location and chunk name can be configured.', async () => {
const { dist } = prepare([
packageJson('build', {
papua: {
injectManifest: { file: './my-worker.ts', chunkName: 'some-worker' },
},
}),
file('index.js', 'console.log("hey")'),
file('my-worker.ts', 'console.log("worker", self.INJECT_MANIFEST_PLUGIN)'),
])

await build(false)

const files = listFilesMatching('**/*', dist)

expect(files).toContain('some-worker.js')
expect(readFile('dist/index.html')).not.toContain('some-worker')

const contents = contentsForFilesMatching('some-worker*.js', dist)

expect(contents[0].contents).not.toContain('self.INJECT_MANIFEST_PLUGIN')
})

test('Installs listed localDependencies.', async () => {
const { dist } = prepare([
packageJson('local-dependencies', {
Expand Down
55 changes: 53 additions & 2 deletions test/stats.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { EOL } from 'os'
import { test, expect, beforeEach, vi } from 'vitest'
import { test, expect, beforeEach, afterEach, vi } from 'vitest'
import {
environment,
prepare,
Expand All @@ -9,9 +9,11 @@ import {
writeFile,
readFile,
} from 'jest-fixture'
import { join } from 'path'
import { build, configure } from '../index'
import { createRspackConfig } from './utility/configuration'

environment('stats')
const [fixturePath] = environment('stats')

const consoleLogMock = vi.fn()
console.log = consoleLogMock
Expand All @@ -20,6 +22,12 @@ beforeEach(() => {
consoleLogMock.mockClear()
})

afterEach(() => {
vi.resetModules()
})

const rspackConfig = createRspackConfig()

test('Stats list all generated assets.', async () => {
const { dist } = prepare([
packageJson('stats-basic'),
Expand Down Expand Up @@ -176,3 +184,46 @@ test('JSX in regular JS will show an error pointing to the source.', async () =>
expect(output).toContain('Expression expected')
expect(output).toContain('<p>hello</p>')
})

test('Entry stats are separated by entries for each configuration.', async () => {
// Virtual mock, so that file doesn't necessarly have to exist.
vi.doMock(join(fixturePath, 'rspack.config.js'), () => rspackConfig)

const { dist } = prepare([
packageJson('stats-multiple-configurations'),
file('first.js', 'console.log("first")'),
file('second.js', 'console.log("second")'),
file('third.js', 'console.log("third")'),
])

// Reset previous imports/mocks.
rspackConfig.default = [
{
entry: { first: { import: './first.js' } },
},
{
entry: { second: { import: './second.js' } },
},
{
entry: { third: { import: './third.js' } },
},
]
// Required for vitest mocking to work properly.
rspackConfig.after = undefined

await build(false)

const files = listFilesMatching('**/*.js', dist)

expect(files.length).toBe(3)

expect(consoleLogMock).toHaveBeenCalled()

const output = consoleLogMock.mock.calls.join(EOL)

// Three separate builds.
expect([...output.matchAll(/Build in/g)].length).toBe(3)
expect([...output.matchAll(/\.\/first\.js \(first\)/g)].length).toBe(1)
expect([...output.matchAll(/\.\/second\.js \(second\)/g)].length).toBe(1)
expect([...output.matchAll(/\.\/third\.js \(third\)/g)].length).toBe(1)
})
3 changes: 2 additions & 1 deletion types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Builtins, RspackOptions } from '@rspack/core'
import type { Options as InjectManifestOptions } from 'inject-manifest-plugin'

type Unpacked<T> = T extends (infer U)[] ? U : T
export type HtmlOptions = Unpacked<Builtins['html']>
Expand Down Expand Up @@ -44,7 +45,7 @@ export interface Options {
typescript: boolean
test: false | string
publicPath: string
injectManifest: Object | false
injectManifest: InjectManifestOptions | false
hasTest: boolean
title: string
html: boolean | HtmlOptions
Expand Down
38 changes: 15 additions & 23 deletions utility/stats.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,33 @@
import chalk from 'chalk'
import prettyMs from 'pretty-ms'
import prettyBytes from 'pretty-bytes'
import { MultiCompiler, MultiStats, Stats } from '@rspack/core'
import { Compiler, MultiStats, Stats } from '@rspack/core'
import { log } from './helper'
import { options } from './options'

export const startServer = (url: string) => {
log(`Starting server on ${url}...`)
}

const getEntries = (compiler: MultiCompiler) => {
const getEntries = (compiler: Compiler) => {
const entries = []

compiler.compilers.forEach((innerCompiler) => {
const { entry } = innerCompiler.compilation.options

Object.keys(entry).forEach((entryKey) => {
entries.push([
entryKey,
// Filter out DevServer injections.
entry[entryKey].import.filter(
(module) =>
!module.includes('node_modules/@rspack') && !module.includes('node_modules/webpack')
),
])
})
const { entry } = compiler.compilation.options

Object.keys(entry).forEach((entryKey) => {
entries.push([
entryKey,
// Filter out DevServer injections.
entry[entryKey].import.filter(
(module) =>
!module.includes('node_modules/@rspack') && !module.includes('node_modules/webpack')
),
])
})

return entries
}

export const logStats = (
input: MultiStats | Stats,
development: boolean,
compiler: MultiCompiler
) => {
export const logStats = (input: MultiStats | Stats, development: boolean) => {
const multiStats: Stats[] =
input instanceof MultiStats ? input.stats : [input as unknown as Stats]
multiStats.forEach((stats) => {
Expand All @@ -49,8 +42,7 @@ export const logStats = (
)
}

const entries = getEntries(compiler)

const entries = getEntries(stats.compilation.compiler)
console.log(
`${chalk.gray('Entry')} ${entries
.map((entry) => `${entry[1].join(', ')} (${entry[0]})`)
Expand Down

0 comments on commit 7dbca48

Please sign in to comment.