Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rebuild when package.json dependencies changed #759

Merged
merged 3 commits into from Nov 3, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/cli-main.ts
@@ -1,8 +1,7 @@
import { readFileSync } from 'fs'
import { join } from 'path'
import { cac } from 'cac'
import flat from 'flat'
import { Format, Options } from '.'
import { version } from '../package.json'
import { slash } from './utils'

function ensureArray(input: string): string[] {
Expand Down Expand Up @@ -58,7 +57,10 @@ export async function main(options: Options = {}) {
'Replace a global variable with an import from another file'
)
.option('--define.* <value>', 'Define compile-time constants')
.option('--external <name>', 'Mark specific packages / package.json (dependencies and peerDependencies) as external')
.option(
'--external <name>',
'Mark specific packages / package.json (dependencies and peerDependencies) as external'
)
.option('--global-name <name>', 'Global variable name for iife format')
.option('--jsxFactory <jsxFactory>', 'Name of JSX factory function', {
default: 'React.createElement',
Expand Down Expand Up @@ -145,8 +147,7 @@ export async function main(options: Options = {}) {

cli.help()

const pkgPath = join(__dirname, '../package.json')
cli.version(JSON.parse(readFileSync(pkgPath, 'utf8')).version)
cli.version(version)

cli.parse(process.argv, { run: false })
await cli.runMatchedCommand()
Expand Down
36 changes: 21 additions & 15 deletions src/esbuild/index.ts
Expand Up @@ -7,7 +7,7 @@ import {
Plugin as EsbuildPlugin,
} from 'esbuild'
import { NormalizedOptions, Format } from '..'
import { getDeps, loadPkg } from '../load'
import { getProductionDeps, loadPkg } from '../load'
import { Logger, getSilent } from '../log'
import { nodeProtocolPlugin } from './node-protocol'
import { externalPlugin } from './external'
Expand Down Expand Up @@ -70,9 +70,11 @@ const generateExternal = async (external: (string | RegExp)[]) => {
continue
}

let pkgPath: string = path.isAbsolute(item) ? path.dirname(item) : path.dirname(path.resolve(process.cwd(), item))
let pkgPath: string = path.isAbsolute(item)
? path.dirname(item)
: path.dirname(path.resolve(process.cwd(), item))

const deps = await getDeps(pkgPath)
const deps = await getProductionDeps(pkgPath)
result.push(...deps)
}

Expand All @@ -96,7 +98,7 @@ export async function runEsbuild(
}
) {
const pkg = await loadPkg(process.cwd())
const deps = await getDeps(process.cwd())
const deps = await getProductionDeps(process.cwd())
const external = [
// Exclude dependencies, e.g. `lodash`, `lodash/get`
...deps.map((dep) => new RegExp(`^${dep}($|\\/|\\\\)`)),
Expand Down Expand Up @@ -124,8 +126,8 @@ export async function runEsbuild(
format === 'iife'
? false
: typeof options.splitting === 'boolean'
? options.splitting
: format === 'esm'
? options.splitting
: format === 'esm'

const platform = options.platform || 'node'
const loader = options.loader || {}
Expand All @@ -152,15 +154,19 @@ export async function runEsbuild(
// esbuild's `external` option doesn't support RegExp
// So here we use a custom plugin to implement it
format !== 'iife' &&
externalPlugin({
external,
noExternal: options.noExternal,
skipNodeModulesBundle: options.skipNodeModulesBundle,
tsconfigResolvePaths: options.tsconfigResolvePaths,
}),
externalPlugin({
external,
noExternal: options.noExternal,
skipNodeModulesBundle: options.skipNodeModulesBundle,
tsconfigResolvePaths: options.tsconfigResolvePaths,
}),
options.tsconfigDecoratorMetadata && swcPlugin({ logger }),
nativeNodeModulesPlugin(),
postcssPlugin({ css, inject: options.injectStyle, cssLoader: loader['.css'] }),
postcssPlugin({
css,
inject: options.injectStyle,
cssLoader: loader['.css'],
}),
sveltePlugin({ css }),
...(options.esbuildPlugins || []),
]
Expand Down Expand Up @@ -220,8 +226,8 @@ export async function runEsbuild(
TSUP_FORMAT: JSON.stringify(format),
...(format === 'cjs' && injectShims
? {
'import.meta.url': 'importMetaUrl',
}
'import.meta.url': 'importMetaUrl',
}
: {}),
...options.define,
...Object.keys(env).reduce((res, key) => {
Expand Down
21 changes: 18 additions & 3 deletions src/index.ts
Expand Up @@ -2,7 +2,7 @@ import path from 'path'
import fs from 'fs'
import { Worker } from 'worker_threads'
import { removeFiles, debouncePromise, slash, MaybePromise } from './utils'
import { loadTsupConfig } from './load'
import { getAllDepsHash, loadTsupConfig } from './load'
import glob from 'globby'
import { loadTsConfig } from 'bundle-require'
import { handleError, PrettyError } from './errors'
Expand Down Expand Up @@ -186,6 +186,8 @@ export async function build(_options: Options) {
/** Files imported by the entry */
const buildDependencies: Set<string> = new Set()

let depsHash = await getAllDepsHash(process.cwd())

const doOnSuccessCleanup = async () => {
if (onSuccessProcess) {
await killProcess({
Expand Down Expand Up @@ -319,14 +321,27 @@ export async function build(_options: Options) {
ignorePermissionErrors: true,
ignored,
})
watcher.on('all', (type, file) => {
watcher.on('all', async (type, file) => {
file = slash(file)
// By default we only rebuild when imported files change
// If you specify custom `watch`, a string or multiple strings
// We rebuild when those files change
if (options.watch === true && !buildDependencies.has(file)) {
let shouldSkipChange = false

if (options.watch === true) {
if (file === 'package.json' && !buildDependencies.has(file)) {
const currentHash = await getAllDepsHash(process.cwd())
shouldSkipChange = currentHash === depsHash
depsHash = currentHash
} else if (!buildDependencies.has(file)) {
shouldSkipChange = true
}
}

if (shouldSkipChange) {
return
}

logger.info('CLI', `Change detected: ${type} ${file}`)
debouncedBuildAll()
})
Expand Down
28 changes: 25 additions & 3 deletions src/load.ts
Expand Up @@ -77,13 +77,22 @@ export async function loadTsupConfig(
return {}
}

export async function loadPkg(cwd: string) {
export async function loadPkg(cwd: string, clearCache: boolean = false) {
if (clearCache) {
joycon.clearCache()
}
const { data } = await joycon.load(['package.json'], cwd, path.dirname(cwd))
return data || {}
}

export async function getDeps(cwd: string) {
const data = await loadPkg(cwd)
/*
* Production deps should be excluded from the bundle
*/
export async function getProductionDeps(
cwd: string,
clearCache: boolean = false
) {
const data = await loadPkg(cwd, clearCache)

const deps = Array.from(
new Set([
Expand All @@ -94,3 +103,16 @@ export async function getDeps(cwd: string) {

return deps
}

/**
* Use this to determine if we should rebuild when package.json changes
*/
export async function getAllDepsHash(cwd: string) {
const data = await loadPkg(cwd, true)

return JSON.stringify({
...data.dependencies,
...data.peerDependencies,
...data.devDependencies,
})
}
6 changes: 3 additions & 3 deletions src/rollup.ts
Expand Up @@ -8,7 +8,7 @@ import { handleError } from './errors'
import { removeFiles } from './utils'
import { TsResolveOptions, tsResolvePlugin } from './rollup/ts-resolve'
import { createLogger, setSilent } from './log'
import { getDeps } from './load'
import { getProductionDeps } from './load'
import path from 'path'
import { reportSize } from './lib/report-size'
import resolveFrom from 'resolve-from'
Expand Down Expand Up @@ -111,7 +111,7 @@ const getRollupConfig = async (
}
}

const deps = await getDeps(process.cwd())
const deps = await getProductionDeps(process.cwd())

const tsupCleanPlugin: Plugin = {
name: 'tsup:clean',
Expand Down Expand Up @@ -174,7 +174,7 @@ const getRollupConfig = async (
external: [
// Exclude dependencies, e.g. `lodash`, `lodash/get`
...deps.map((dep) => new RegExp(`^${dep}($|\\/|\\\\)`)),
...(options.external || [])
...(options.external || []),
],
},
outputConfig: {
Expand Down
18 changes: 9 additions & 9 deletions test/__snapshots__/index.test.ts.snap
Expand Up @@ -167,6 +167,15 @@ console.log(import_node_fs.default);
"
`;

exports[`not bundle \`package/subpath\` in dts (resolve) 1`] = `
"import * as foo_bar from 'foo/bar';

declare const stuff: foo_bar.Foobar;

export { stuff };
"
`;

exports[`simple 1`] = `
"\\"use strict\\";
var __defProp = Object.defineProperty;
Expand Down Expand Up @@ -204,15 +213,6 @@ var input_default = foo_default;
"
`;

exports[`not bundle \`package/subpath\` in dts (resolve) 1`] = `
"import * as foo_bar from 'foo/bar';

declare const stuff: foo_bar.Foobar;

export { stuff };
"
`;

exports[`support baseUrl and paths in tsconfig.json 1`] = `
"var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
Expand Down