Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions __tests__/appconfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ describe('app config', () => {
const output = resolved.build.rollupOptions.output as OutputOptions
expect(typeof output?.assetFileNames).toBe('function')
const assetFileNames = output?.assetFileNames as ((chunkInfo: unknown) => string)
expect(assetFileNames({ name: 'some.css' })).toMatch(/^css\/[^/]+\.css/)
expect(assetFileNames({ name: 'other/file.css' })).toMatch(/^css\/[^/]+\.css/)
expect(assetFileNames({ names: ['some.css'] })).toMatch(/^css\/[^/]+\.css/)
expect(assetFileNames({ names: ['other/file.css'] })).toMatch(/^css\/[^/]+\.css/)
})

it('moves image assets to img/', async () => {
Expand All @@ -60,10 +60,10 @@ describe('app config', () => {
const output = resolved.build.rollupOptions.output as OutputOptions
expect(typeof output?.assetFileNames).toBe('function')
const assetFileNames = output?.assetFileNames as ((chunkInfo: unknown) => string)
expect(assetFileNames({ name: 'some.png' })).toBe('img/[name][extname]')
expect(assetFileNames({ name: 'some.svg' })).toBe('img/[name][extname]')
expect(assetFileNames({ name: 'some.jpg' })).toBe('img/[name][extname]')
expect(assetFileNames({ name: 'some.ico' })).toBe('img/[name][extname]')
expect(assetFileNames({ names: ['some.png'] })).toBe('img/[name][extname]')
expect(assetFileNames({ names: ['some.svg'] })).toBe('img/[name][extname]')
expect(assetFileNames({ names: ['some.jpg'] })).toBe('img/[name][extname]')
expect(assetFileNames({ names: ['some.ico'] })).toBe('img/[name][extname]')
})

it('moves fonts to css/fonts', async () => {
Expand All @@ -72,20 +72,20 @@ describe('app config', () => {
const output = resolved.build.rollupOptions.output as OutputOptions
expect(typeof output?.assetFileNames).toBe('function')
const assetFileNames = output?.assetFileNames as ((chunkInfo: unknown) => string)
expect(assetFileNames({ name: 'some.woff' })).toBe('css/fonts/[name][extname]')
expect(assetFileNames({ name: 'some.woff2' })).toBe('css/fonts/[name][extname]')
expect(assetFileNames({ name: 'some.otf' })).toBe('css/fonts/[name][extname]')
expect(assetFileNames({ name: 'some.ttf' })).toBe('css/fonts/[name][extname]')
expect(assetFileNames({ names: ['some.woff'] })).toBe('css/fonts/[name][extname]')
expect(assetFileNames({ names: ['some.woff2'] })).toBe('css/fonts/[name][extname]')
expect(assetFileNames({ names: ['some.otf'] })).toBe('css/fonts/[name][extname]')
expect(assetFileNames({ names: ['some.ttf'] })).toBe('css/fonts/[name][extname]')
})

it('allow custom asset names', async () => {
const resolved = await createConfig('build', 'development', { assetFileNames: (({ name }) => name === 'main.png' ? 'img/main.png' : undefined) as never })
const resolved = await createConfig('build', 'development', { assetFileNames: ({ names }) => names[0] === 'main.png' ? 'img/main.png' : undefined })

const output = resolved.build.rollupOptions.output as OutputOptions
expect(typeof output?.assetFileNames).toBe('function')
const assetFileNames = output?.assetFileNames as ((chunkInfo: unknown) => string)
expect(assetFileNames({ name: 'main.png' })).toBe('img/main.png')
expect(assetFileNames({ name: 'foo.png' })).toBe('img/[name][extname]')
expect(assetFileNames({ names: ['main.png'] })).toBe('img/main.png')
expect(assetFileNames({ names: ['foo.png'] })).toBe('img/[name][extname]')
})

it('extracts CSS by default with CSS entry points', async () => {
Expand Down
27 changes: 16 additions & 11 deletions __tests__/libconfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { ESBuildOptions, resolveConfig } from 'vite'
import { ESBuildOptions, resolveConfig, Rollup } from 'vite'
import { describe, it, expect } from 'vitest'
import { LibraryOptions, createLibConfig } from '../lib/libConfig'

Expand Down Expand Up @@ -50,25 +50,30 @@ describe('library config', () => {
it('keep name without inlining the CSS assets ', async () => {
const resolved = await createConfig('build', 'development')

expect(resolved.build.rollupOptions.output?.[0].assetFileNames).not.toBe(undefined)
expect(resolved.build.rollupOptions.output?.[0].assetFileNames({ name: 'some.css' })).toBe('[name].css')
expect(resolved.build.rollupOptions.output?.[0].assetFileNames({ name: 'some.nfo' })).toBe('assets/[name]-[hash][extname]')
const [output] = resolved.build.rollupOptions.output! as Rollup.OutputOptions[]
expect(output.assetFileNames).not.toBe(undefined)
expect(output.assetFileNames({ names: ['some.css'] })).toBe('[name].css')
expect(output.assetFileNames({ names: ['some.nfo'] })).toBe('assets/[name]-[hash][extname]')
})

it('move CSS files to asset directory when inlining CSS', async () => {
const resolved = await createConfig('build', 'development', { inlineCSS: true })

expect(resolved.build.rollupOptions.output?.[0].assetFileNames).not.toBe(undefined)
expect(resolved.build.rollupOptions.output?.[0].assetFileNames({ name: 'some.css' })).toBe('assets/[name]-[hash][extname]')
expect(resolved.build.rollupOptions.output?.[0].assetFileNames({ name: 'some.nfo' })).toBe('assets/[name]-[hash][extname]')
const [output] = resolved.build.rollupOptions.output! as Rollup.OutputOptions[]
expect(output.assetFileNames).not.toBe(undefined)
expect(output.assetFileNames({ names: ['some.css'] })).toBe('assets/[name]-[hash][extname]')
expect(output.assetFileNames({ names: ['some.nfo'] })).toBe('assets/[name]-[hash][extname]')
})

it('allow custom asset names', async () => {
const resolved = await createConfig('build', 'development', { assetFileNames: (({ name }) => name === 'foo.css' ? 'bar.css' : undefined) as never })
const resolved = await createConfig('build', 'development', {
assetFileNames: ((assetInfo: Rollup.PreRenderedAsset) => assetInfo.names.includes('foo.css') ? 'bar.css' : undefined) as never,
})

expect(resolved.build.rollupOptions.output?.[0].assetFileNames).not.toBe(undefined)
expect(resolved.build.rollupOptions.output?.[0].assetFileNames({ name: 'foo.css' })).toBe('bar.css')
expect(resolved.build.rollupOptions.output?.[0].assetFileNames({ name: 'baz.css' })).toBe('[name].css')
const [output] = resolved.build.rollupOptions.output! as Rollup.OutputOptions[]
expect(output.assetFileNames).not.toBe(undefined)
expect(output.assetFileNames({ names: ['foo.css'] })).toBe('bar.css')
expect(output.assetFileNames({ names: ['baz.css'] })).toBe('[name].css')
})
})

Expand Down
21 changes: 16 additions & 5 deletions lib/appConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/**
* SPDX-FileCopyrightText: 2023 Ferdinand Thiessen <opensource@fthiessen.de>
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

Expand All @@ -12,6 +11,7 @@ import { readFileSync } from 'node:fs'
import { relative } from 'node:path'
import { cwd } from 'node:process'
import { mergeConfig } from 'vite'
import * as vite from 'vite'
import { createBaseConfig } from './baseConfig.js'
import { findAppinfo } from './utils/appinfo.js'

Expand Down Expand Up @@ -223,7 +223,8 @@ export const createAppConfig = (entries: { [entryAlias: string]: string }, optio
}
}

const extType = assetInfo.name.split('.').pop()
const [name] = assetInfo.names
const extType = name.split('.').pop()
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
return 'img/[name][extname]'
} else if (/css/i.test(extType)) {
Expand All @@ -243,9 +244,19 @@ export const createAppConfig = (entries: { [entryAlias: string]: string }, optio
chunkFileNames: () => {
return 'js/[name]-[hash].chunk.mjs'
},
manualChunks: {
...(options?.coreJS ? { polyfill: ['core-js'] } : {}),
},
...(
options?.coreJS
? (
'rolldownVite' in vite
? {
advancedChunks: {
groups: [{ name: 'polyfill', test: /core-js/ }],
},
}
: { polyfill: ['core-js'] }
)
: {}
),
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion lib/baseConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface BaseOptions {
* but if returns undefined, then this config defaults is be used.
*
* @example Move CSS styles to `styles/style.css` instead of the default `css/[entrypoint-name].css`:
* (chunkInfo) => chunkInfo.name.endsWith('.css') ? 'styles/style.css' : undefined
* (chunkInfo) => chunkInfo.names[0].endsWith('.css') ? 'styles/style.css' : undefined
*/
assetFileNames?: (chunkInfo: Rollup.PreRenderedAsset) => string | undefined,
/**
Expand Down
7 changes: 4 additions & 3 deletions lib/libConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { LibraryFormats, UserConfig, UserConfigFn, BuildOptions, Plugin } from 'vite'
import type { LibraryFormats, UserConfig, UserConfigFn, BuildOptions, Plugin, Rollup } from 'vite'
import type { BaseOptions } from './baseConfig.js'

import { mergeConfig } from 'vite'
Expand Down Expand Up @@ -110,7 +110,7 @@ export const createLibConfig = (entries: { [entryAlias: string]: string }, optio
plugins.push(DTSPlugin(options.DTSPluginOptions))
}

const assetFileNames = (assetInfo) => {
const assetFileNames = (assetInfo: Rollup.PreRenderedAsset) => {
// Allow to customize the asset file names
if (options.assetFileNames) {
const customName = options.assetFileNames(assetInfo)
Expand All @@ -119,7 +119,8 @@ export const createLibConfig = (entries: { [entryAlias: string]: string }, optio
}
}

const extType = assetInfo.name.split('.').pop()
const [name] = assetInfo.names
const extType = name.split('.').pop()
if (!options.inlineCSS && /css/i.test(extType)) {
return '[name].css'
}
Expand Down
4 changes: 2 additions & 2 deletions lib/plugins/CSSEntryPoints.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/**
* SPDX-FileCopyrightText: 2024 Ferdinand Thiessen <opensource@fthiessen.de>
*
* SPDX-License-Identifier: MIT
*/

Expand Down Expand Up @@ -44,7 +43,8 @@ export function CSSEntryPointsPlugin(options?: CSSEntryPointsPluginOptions) {
// If the original assets name option is a function we need to call it otherwise just use the template string
const name = typeof config === 'function' ? config(info) : config
// Only handle CSS files not extracted by this plugin
if (info.name.endsWith('.css') && !String(info.source).startsWith('/* extracted by css-entry-points-plugin */')) {
const [assetName] = info.names
if (assetName.endsWith('.css') && !String(info.source).startsWith('/* extracted by css-entry-points-plugin */')) {
// The new name should have the same path but instead of the .css extension it is .chunk.css
return name.replace(/(.css|.\[ext\]|\[extname\])$/, '.chunk.css')
}
Expand Down