Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

fix: allow Node modules to be excluded from the bundle #673

Merged
merged 4 commits into from
Oct 6, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 7 additions & 0 deletions src/node_dependencies/traverse.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ const getDependencyNamesAndPathsForDependencies = async function ({
state = getNewCache(),
pluginsModulesPath,
}) {
if (dependencyNames.length === 0) {
return {
moduleNames: [],
paths: [],
}
}

const packageJson = await getPackageJson(basedir)
const dependencies = await Promise.all(
dependencyNames.map((dependencyName) =>
Expand Down
51 changes: 32 additions & 19 deletions src/runtimes/node/src_files.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
const { normalize } = require('path')
const { normalize, resolve } = require('path')
const { promisify } = require('util')

const glob = require('glob')
const minimatch = require('minimatch')

const pGlob = promisify(glob)

const { getDependencyNamesAndPathsForDependencies, listFilesUsingLegacyBundler } = require('../../node_dependencies')
const { JS_BUNDLER_ZISI } = require('../../utils/consts')

// Returns the subset of `paths` that don't match any of the glob expressions
// from `exclude`.
const filterExcludedPaths = (paths, exclude = []) => {
if (exclude.length === 0) {
return paths
}

const excludedPaths = paths.filter((path) => !exclude.some((pattern) => minimatch(path, pattern)))

return excludedPaths
}

const getPathsOfIncludedFiles = async (includedFiles, basePath) => {
// Some of the globs in `includedFiles` might be exclusion patterns, which
// means paths that should NOT be included in the bundle. We need to treat
Expand All @@ -16,9 +29,11 @@ const getPathsOfIncludedFiles = async (includedFiles, basePath) => {
const { include, exclude } = includedFiles.reduce(
(acc, path) => {
if (path.startsWith('!')) {
const excludePath = resolve(basePath, path.slice(1))

return {
...acc,
exclude: [...acc.exclude, path.slice(1)],
exclude: [...acc.exclude, excludePath],
}
}

Expand All @@ -38,7 +53,7 @@ const getPathsOfIncludedFiles = async (includedFiles, basePath) => {
const paths = pathGroups.flat()
const normalizedPaths = paths.map(normalize)

return [...new Set(normalizedPaths)]
return { exclude, paths: [...new Set(normalizedPaths)] }
}

const getSrcFiles = async function ({ config, ...parameters }) {
Expand All @@ -62,38 +77,36 @@ const getSrcFilesAndExternalModules = async function ({
srcPath,
stat,
}) {
const includedFilePaths = await getPathsOfIncludedFiles(includedFiles, includedFilesBasePath)
const { exclude: excludedPaths, paths: includedFilePaths } = await getPathsOfIncludedFiles(
includedFiles,
includedFilesBasePath,
)

if (bundler === JS_BUNDLER_ZISI) {
const paths = await listFilesUsingLegacyBundler({
const dependencyPaths = await listFilesUsingLegacyBundler({
featureFlags,
srcPath,
mainFile,
srcDir,
stat,
pluginsModulesPath,
})
const includedPaths = filterExcludedPaths([...dependencyPaths, ...includedFilePaths], excludedPaths)

return {
moduleNames: [],
paths: [...paths, ...includedFilePaths],
paths: includedPaths,
}
}

if (externalNodeModules.length !== 0) {
const { moduleNames, paths } = await getDependencyNamesAndPathsForDependencies({
dependencies: externalNodeModules,
basedir: srcDir,
pluginsModulesPath,
})

return { moduleNames, paths: [...paths, ...includedFilePaths, mainFile] }
}
const { moduleNames, paths: dependencyPaths } = await getDependencyNamesAndPathsForDependencies({
dependencies: externalNodeModules,
basedir: srcDir,
pluginsModulesPath,
})
const includedPaths = filterExcludedPaths([...dependencyPaths, ...includedFilePaths], excludedPaths)

return {
moduleNames: externalNodeModules,
paths: [mainFile, ...includedFilePaths],
}
return { moduleNames, paths: [...includedPaths, mainFile] }
}

module.exports = { getSrcFiles, getSrcFilesAndExternalModules }
23 changes: 23 additions & 0 deletions tests/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,29 @@ test('Negated files in `included_files` are excluded from the bundle even if the
t.throws(() => func('en'))
})

testBundlers(
'Negated files in `included_files` are excluded from the bundle even if they match Node modules required in a function',
[ESBUILD, DEFAULT],
async (bundler, t) => {
const fixtureName = 'node-module-included-try-catch'
const { tmpDir } = await zipNode(t, fixtureName, {
opts: {
basePath: join(FIXTURES_DIR, fixtureName),
config: {
'*': {
externalNodeModules: ['test'],
includedFiles: ['!node_modules/test/**'],
nodeBundler: bundler,
},
},
},
})

t.true(await pathExists(`${tmpDir}/function.js`))
t.false(await pathExists(`${tmpDir}/node_modules/test/index.js`))
},
)

test('Creates dynamic import shims for functions with the same name and same shim contents with no naming conflicts', async (t) => {
const FUNCTION_COUNT = 30
const fixtureName = 'node-module-dynamic-import-3'
Expand Down