Compare commits

...

3 Commits

Author SHA1 Message Date
GitHub Actions 71743b3bf3 chore(release): v0.5.3 2023-09-19 21:40:41 +00:00
Aaron 8e3169eb1e chore: Refactor how config is resolved (#118) 2023-09-19 16:36:00 -05:00
Aaron Klinker 4ec904ea3c fix: Allow function for vite config 2023-09-19 12:53:35 -05:00
11 changed files with 234 additions and 165 deletions
+17
View File
@@ -1,5 +1,22 @@
# Changelog
## v0.5.3
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.2...v0.5.3)
### 🩹 Fixes
- Allow function for vite config ([4ec904e](https://github.com/wxt-dev/wxt/commit/4ec904e))
### 🏡 Chore
- Refactor how config is resolved ([#118](https://github.com/wxt-dev/wxt/pull/118))
### ❤️ Contributors
- Aaron <aaronklinker1@gmail.com>
- Aaron Klinker <aaronklinker1@gmail.com>
## v0.5.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.5.1...v0.5.2)
-3
View File
@@ -2,9 +2,6 @@ import { defineConfig } from 'wxt';
export default defineConfig({
srcDir: 'src',
storeIds: {
chrome: '123',
},
manifest: {
default_locale: 'en',
},
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.5.2",
"version": "0.5.3",
"description": "Next gen framework for developing web extensions",
"engines": {
"node": ">=18.16.0",
+1 -2
View File
@@ -14,10 +14,9 @@ export const build = defineCommand<
},
]
>(async (root, flags) => {
const mode = flags.mode ?? 'production';
const cliConfig: wxt.InlineConfig = {
root,
mode,
mode: flags.mode,
browser: flags.browser,
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
configFile: flags.config,
+1 -2
View File
@@ -14,10 +14,9 @@ export const dev = defineCommand<
},
]
>(async (root, flags) => {
const mode = flags.mode ?? 'development';
const cliConfig: wxt.InlineConfig = {
root,
mode,
mode: flags.mode,
browser: flags.browser,
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
configFile: flags.config,
+1 -2
View File
@@ -17,10 +17,9 @@ export const zip = defineCommand<
},
]
>(async (root, flags) => {
const mode = flags.mode ?? 'production';
const cliConfig: wxt.InlineConfig = {
root,
mode,
mode: flags.mode,
browser: flags.browser,
manifestVersion: flags.mv3 ? 3 : flags.mv2 ? 2 : undefined,
configFile: flags.config,
+8 -9
View File
@@ -43,14 +43,6 @@ export interface InlineConfig {
* @default false
*/
debug?: boolean;
/**
* ID of the extension for each store. Used for publishing.
*/
storeIds?: {
chrome?: string;
firefox?: string;
edge?: string;
};
/**
* Explicitly set a mode to run in. This will override the default mode for each command, and can
* be overridden by the command line `--mode` option.
@@ -95,7 +87,9 @@ export interface InlineConfig {
*
* [`root`](#root), [`configFile`](#configfile), and [`mode`](#mode) should be set in WXT's config.
*/
vite?: Omit<vite.UserConfig, 'root' | 'configFile' | 'mode'>;
vite?:
| WxtViteConfig
| ((env: ConfigEnv) => WxtViteConfig | Promise<WxtViteConfig>);
/**
* Customize the `manifest.json` output. Can be an object, promise, or function that returns an
* object or promise.
@@ -484,3 +478,8 @@ export interface ExtensionRunnerConfig {
*/
startUrls?: string[];
}
export type WxtViteConfig = Omit<
vite.UserConfig,
'root' | 'configFile' | 'mode'
>;
-5
View File
@@ -21,11 +21,6 @@ export interface InternalConfig {
outBaseDir: string;
outDir: string;
debug: boolean;
storeIds: {
chrome?: string;
firefox?: string;
edge?: string;
};
mode: string;
command: 'build' | 'serve';
browser: TargetBrowser;
+198 -134
View File
@@ -1,176 +1,115 @@
import { loadConfig } from 'c12';
import {
ConfigEnv,
ExtensionRunnerConfig,
InlineConfig,
InternalConfig,
UserConfig,
UserManifest,
ConfigEnv,
UserManifestFn,
UserManifest,
WxtViteConfig,
ExtensionRunnerConfig,
} from '../types';
import path, { resolve } from 'node:path';
import path from 'node:path';
import * as vite from 'vite';
import { LogLevels, consola } from 'consola';
import * as plugins from '../vite-plugins';
import { createFsCache } from './createFsCache';
import consola, { LogLevels } from 'consola';
import * as plugins from '../vite-plugins';
import { getGlobals } from './globals';
import { loadConfig } from 'c12';
/**
* Given an inline config, discover the config file if necessary, merge the results, resolve any
* relative paths, and apply any defaults.
*
* Inline config always has priority over user config. Cli flags are passed as inline config if set.
* If unset, undefined is passed in, letting this function decide default values.
*/
export async function getInternalConfig(
config: InlineConfig,
inlineConfig: InlineConfig,
command: 'build' | 'serve',
): Promise<InternalConfig> {
// Apply defaults to a base config
const root = config.root ? path.resolve(config.root) : process.cwd();
const mode =
config.mode ?? (command === 'build' ? 'production' : 'development');
const browser = config.browser ?? 'chrome';
const manifestVersion =
config.manifestVersion ?? (browser == 'firefox' ? 2 : 3);
const outBaseDir = path.resolve(root, '.output');
const outDir = path.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
const logger = config.logger ?? consola;
const debug = !!config.debug;
if (debug) logger.level = LogLevels.debug;
// Load user config
const baseConfig: InternalConfigNoUserDirs = {
root,
outDir,
outBaseDir,
storeIds: config.storeIds ?? {},
browser,
manifestVersion,
mode,
command,
debug,
logger,
vite: config.vite ?? {},
imports: config.imports ?? {},
runnerConfig: await loadConfig<ExtensionRunnerConfig>({
name: 'web-ext',
cwd: root,
globalRc: true,
rcFile: '.webextrc',
overrides: config.runner,
}),
};
// Load user config from file
let userConfig: UserConfig = {
mode,
};
if (config.configFile !== false) {
let userConfig: UserConfig = {};
if (inlineConfig.configFile !== false) {
const loaded = await loadConfig<UserConfig>({
name: 'wxt',
cwd: root,
cwd: inlineConfig.root ?? process.cwd(),
rcFile: false,
});
userConfig = loaded.config ?? {};
}
// Merge inline and user configs
const merged = vite.mergeConfig(
baseConfig,
userConfig,
) as InternalConfigNoUserDirs;
// Merge it into the inline config
// Apply user config and create final config
const srcDir = userConfig.srcDir ? resolve(root, userConfig.srcDir) : root;
const entrypointsDir = resolve(
srcDir,
userConfig.entrypointsDir ?? 'entrypoints',
const mergedConfig = mergeInlineConfig(inlineConfig, userConfig);
// Apply defaults to make internal config.
const debug = mergedConfig.debug ?? false;
const logger = mergedConfig.logger ?? consola;
if (debug) logger.level = LogLevels.debug;
const browser = mergedConfig.browser ?? 'chrome';
const manifestVersion =
mergedConfig.manifestVersion ?? (browser == 'firefox' ? 2 : 3);
const mode =
mergedConfig.mode ?? (command === 'build' ? 'production' : 'development');
const env: ConfigEnv = { browser, command, manifestVersion, mode };
const root = path.resolve(
inlineConfig.root ?? userConfig.root ?? process.cwd(),
);
const publicDir = resolve(srcDir, userConfig.publicDir ?? 'public');
const wxtDir = resolve(root, '.wxt');
const typesDir = resolve(wxtDir, 'types');
const wxtDir = path.resolve(root, '.wxt');
const srcDir = path.resolve(root, mergedConfig.srcDir ?? root);
const entrypointsDir = path.resolve(
srcDir,
mergedConfig.entrypointsDir ?? 'entrypoints',
);
const publicDir = path.resolve(srcDir, mergedConfig.publicDir ?? 'public');
const typesDir = path.resolve(wxtDir, 'types');
const outBaseDir = path.resolve(root, '.output');
const outDir = path.resolve(outBaseDir, `${browser}-mv${manifestVersion}`);
// Merge manifest sources
const env: ConfigEnv = { mode, browser, manifestVersion, command };
const userManifest = await resolveManifestConfig(env, userConfig.manifest);
const inlineManifest = await resolveManifestConfig(env, config.manifest);
const manifest = vite.mergeConfig(userManifest, inlineManifest);
const runnerConfig = await loadConfig<ExtensionRunnerConfig>({
name: 'web-ext',
cwd: root,
globalRc: true,
rcFile: '.webextrc',
overrides: mergedConfig.runner,
});
const finalConfig: InternalConfig = {
...merged,
srcDir,
browser,
command,
debug,
entrypointsDir,
publicDir,
wxtDir: wxtDir,
typesDir,
fsCache: createFsCache(wxtDir),
manifest,
zip: {
sourcesTemplate: '{{name}}-{{version}}-sources.zip',
artifactTemplate: '{{name}}-{{version}}-{{browser}}.zip',
sourcesRoot: root,
...userConfig.zip,
...config.zip,
ignoredSources: [
'**/node_modules',
// WXT files
'**/web-ext.config.ts',
// Hidden files
'**/.*',
// Tests
'**/__tests__/**',
'**/*.+(test|spec).?(c|m)+(j|t)s?(x)',
// User config
...(userConfig.zip?.ignoredSources ?? []),
...(config.zip?.ignoredSources ?? []),
],
},
imports: mergedConfig.imports ?? {},
logger,
manifest: await resolveManifestConfig(env, mergedConfig.manifest),
manifestVersion,
mode,
outBaseDir,
outDir,
publicDir,
root,
runnerConfig,
srcDir,
typesDir,
vite: {}, // Real value added after this object is initialized.
wxtDir,
zip: resolveInternalZipConfig(root, mergedConfig),
};
// Customize the default vite config
finalConfig.vite.root = root;
finalConfig.vite.configFile = false;
finalConfig.vite.logLevel = 'warn';
finalConfig.vite.build ??= {};
finalConfig.vite.build.outDir = outDir;
finalConfig.vite.build.emptyOutDir = false;
finalConfig.vite.plugins ??= [];
finalConfig.vite.plugins.push(plugins.download(finalConfig));
finalConfig.vite.plugins.push(plugins.devHtmlPrerender(finalConfig));
finalConfig.vite.plugins.push(plugins.unimport(finalConfig));
finalConfig.vite.plugins.push(
plugins.virtualEntrypoin('background', finalConfig),
finalConfig.vite = await resolveInternalViteConfig(
env,
mergedConfig,
finalConfig,
);
finalConfig.vite.plugins.push(
plugins.virtualEntrypoin('content-script', finalConfig),
);
finalConfig.vite.plugins.push(plugins.devServerGlobals(finalConfig));
finalConfig.vite.plugins.push(plugins.tsconfigPaths(finalConfig));
finalConfig.vite.plugins.push(plugins.noopBackground());
finalConfig.vite.define ??= {};
getGlobals(finalConfig).forEach((global) => {
finalConfig.vite.define![global.name] = JSON.stringify(global.value);
});
return finalConfig;
}
/**
* Helper type for defining a base config, since user-configurable directories must be set after
* reading in the user config.
*/
type InternalConfigNoUserDirs = Omit<
InternalConfig,
| 'srcDir'
| 'publicDir'
| 'entrypointsDir'
| 'wxtDir'
| 'typesDir'
| 'fsCache'
| 'manifest'
| 'zip'
>;
async function resolveManifestConfig(
env: ConfigEnv,
manifest: UserManifest | Promise<UserManifest> | UserManifestFn | undefined,
@@ -179,3 +118,128 @@ async function resolveManifestConfig(
? manifest(env)
: manifest ?? {});
}
/**
* Merge the inline config and user config. Inline config is given priority. Defaults are not applied here.
*/
function mergeInlineConfig(
inlineConfig: InlineConfig,
userConfig: UserConfig,
): InlineConfig {
let imports: InlineConfig['imports'];
if (inlineConfig.imports === false || userConfig.imports === false) {
imports = false;
} else if (userConfig.imports == null && inlineConfig.imports == null) {
imports = undefined;
} else {
imports = vite.mergeConfig(
userConfig.imports ?? {},
inlineConfig.imports ?? {},
);
}
const manifest: UserManifestFn = async (env) => {
const user = await resolveManifestConfig(env, userConfig.manifest);
const inline = await resolveManifestConfig(env, inlineConfig.manifest);
return vite.mergeConfig(user, inline);
};
const viteConfig = async (env: ConfigEnv): Promise<WxtViteConfig> => {
const user = await resolveViteConfig(env, userConfig.vite);
const inline = await resolveViteConfig(env, inlineConfig.vite);
return vite.mergeConfig(user, inline);
};
const runner: InlineConfig['runner'] = vite.mergeConfig(
userConfig.runner ?? {},
inlineConfig.runner ?? {},
);
const zip: InlineConfig['zip'] = vite.mergeConfig(
userConfig.zip ?? {},
inlineConfig.zip ?? {},
);
return {
root: inlineConfig.root ?? userConfig.root,
browser: inlineConfig.browser ?? userConfig.browser,
manifestVersion: inlineConfig.manifestVersion ?? userConfig.manifestVersion,
configFile: inlineConfig.configFile,
debug: inlineConfig.debug ?? userConfig.debug,
entrypointsDir: inlineConfig.entrypointsDir ?? userConfig.entrypointsDir,
imports,
logger: inlineConfig.logger ?? userConfig.logger,
manifest,
mode: inlineConfig.mode ?? userConfig.mode,
publicDir: inlineConfig.publicDir ?? userConfig.publicDir,
runner,
srcDir: inlineConfig.srcDir ?? userConfig.srcDir,
vite: viteConfig,
zip,
};
}
async function resolveViteConfig(
env: ConfigEnv,
vite: InlineConfig['vite'],
): Promise<WxtViteConfig> {
return await (typeof vite === 'function' ? vite(env) : vite ?? {});
}
function resolveInternalZipConfig(
root: string,
mergedConfig: InlineConfig,
): InternalConfig['zip'] {
return {
sourcesTemplate: '{{name}}-{{version}}-sources.zip',
artifactTemplate: '{{name}}-{{version}}-{{browser}}.zip',
sourcesRoot: root,
...mergedConfig.zip,
ignoredSources: [
'**/node_modules',
// WXT files
'**/web-ext.config.ts',
// Hidden files
'**/.*',
// Tests
'**/__tests__/**',
'**/*.+(test|spec).?(c|m)+(j|t)s?(x)',
// From user
...(mergedConfig.zip?.ignoredSources ?? []),
],
};
}
async function resolveInternalViteConfig(
env: ConfigEnv,
mergedConfig: InlineConfig,
finalConfig: InternalConfig,
) {
const internalVite: vite.InlineConfig = await resolveViteConfig(
env,
mergedConfig.vite,
);
internalVite.root = finalConfig.root;
internalVite.configFile = false;
internalVite.logLevel = 'warn';
internalVite.build ??= {};
internalVite.build.outDir = finalConfig.outDir;
internalVite.build.emptyOutDir = false;
internalVite.plugins ??= [];
internalVite.plugins.push(plugins.download(finalConfig));
internalVite.plugins.push(plugins.devHtmlPrerender(finalConfig));
internalVite.plugins.push(plugins.unimport(finalConfig));
internalVite.plugins.push(
plugins.virtualEntrypoin('background', finalConfig),
);
internalVite.plugins.push(
plugins.virtualEntrypoin('content-script', finalConfig),
);
internalVite.plugins.push(plugins.devServerGlobals(finalConfig));
internalVite.plugins.push(plugins.tsconfigPaths(finalConfig));
internalVite.plugins.push(plugins.noopBackground());
internalVite.define ??= {};
for (const global of getGlobals(finalConfig)) {
internalVite.define[global.name] = JSON.stringify(global.value);
}
return internalVite;
}
+7 -6
View File
@@ -1,7 +1,6 @@
import { BuildOutput, WxtDevServer, InlineConfig } from './core/types';
import { getInternalConfig } from './core/utils/getInternalConfig';
import pc from 'picocolors';
import * as vite from 'vite';
import { detectDevChanges } from './core/utils/detectDevChanges';
import { Mutex } from 'async-mutex';
import { consola } from 'consola';
@@ -38,12 +37,14 @@ export async function createServer(
): Promise<WxtDevServer> {
const serverInfo = await getServerInfo();
const getLatestInternalConfig = () => {
const viteConfig: vite.InlineConfig = vite.mergeConfig(
serverInfo.viteServerConfig,
config?.vite ?? {},
const getLatestInternalConfig = async () => {
return getInternalConfig(
{
...config,
vite: serverInfo.viteServerConfig,
},
'serve',
);
return getInternalConfig({ ...config, vite: viteConfig }, 'serve');
};
let internalConfig = await getLatestInternalConfig();
-1
View File
@@ -217,7 +217,6 @@ export const fakeInternalConfig = fakeObjectCreator<InternalConfig>(() => ({
},
debug: faker.datatype.boolean(),
srcDir: fakeDir(),
storeIds: {},
typesDir: fakeDir(),
vite: {},
wxtDir: fakeDir(),