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

Commit

Permalink
feat(js): add list of tree shakable external dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
erezrokah committed Dec 10, 2020
1 parent 103fef5 commit 8756520
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 11 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ zip-it-and-ship-it*
.nyc_output
coverage
.eslintcache
.vscode
61 changes: 50 additions & 11 deletions src/dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const getDependencies = async function(mainFile, srcDir) {
const packageRoot = await pkgDir(srcDir)
const packageJson = getPackageJson(packageRoot)

const state = { localFiles: [], modulePaths: [] }
const state = { localFiles: new Set(), modulePaths: new Set() }

try {
return await getFileDependencies(mainFile, packageJson, state)
Expand All @@ -71,11 +71,11 @@ const getPackageJson = function(packageRoot) {
}

const getFileDependencies = async function(path, packageJson, state) {
if (state.localFiles.includes(path)) {
if (state.localFiles.has(path)) {
return []
}

state.localFiles.push(path)
state.localFiles.add(path)

const basedir = dirname(path)
// This parses JavaScript in `path` to retrieve all the `require()` statements
Expand All @@ -92,25 +92,64 @@ const getFileDependencies = async function(path, packageJson, state) {
// `require()` statements can be either `require('moduleName')` or
// `require(path)`
const getImportDependencies = function(dependency, basedir, packageJson, state) {
if (LOCAL_IMPORT_REGEXP.test(dependency)) {
return getLocalImportDependencies(dependency, basedir, packageJson, state)
if (LOCAL_IMPORT_REGEXP.test(dependency) || isTreeShakable(dependency)) {
return getTreeShakedDependencies(dependency, basedir, packageJson, state)
}

return getModuleDependencies(dependency, basedir, state, packageJson)
return getAllDependencies(dependency, basedir, state, packageJson)
}

const LOCAL_IMPORT_REGEXP = /^(\.|\/)/

const isTreeShakable = function(dependency) {
if (dependency.includes('next') && !TREE_SHAKABLE_DEPENDENCIES.has(dependency)) {
console.log(dependency)
}
return TREE_SHAKABLE_DEPENDENCIES.has(dependency)
}

const TREE_SHAKABLE_DEPENDENCIES = new Set([
'@next/env',
'next/dist/compiled/chalk',
'next/dist/compiled/content-type',
'next/dist/compiled/cookie',
'next/dist/compiled/escape-string-regexp',
'next/dist/compiled/etag',
'next/dist/compiled/fresh',
'next/dist/compiled/jsonwebtoken',
'next/dist/compiled/node-fetch',
'next/dist/compiled/path-to-regexp',
'next/dist/compiled/raw-body',
'next/dist/compiled/semver',
'next/dist/next-server/lib/constants',
'next/dist/next-server/lib/constants.js',
'next/dist/next-server/lib/document-context.js',
'next/dist/next-server/lib/head.js',
'next/dist/next-server/lib/i18n/normalize-locale-path',
'next/dist/next-server/lib/router/utils/get-route-from-asset-path',
'next/dist/next-server/lib/router/utils/path-match',
'next/dist/next-server/lib/router/utils/prepare-destination',
'next/dist/next-server/lib/utils',
'next/dist/next-server/lib/utils.js',
'next/dist/next-server/server/api-utils',
'next/dist/next-server/server/denormalize-page-path',
'next/dist/next-server/server/get-page-files.js',
'next/dist/next-server/server/node-polyfill-fetch',
'next/dist/next-server/server/render',
'next/dist/next-server/server/send-payload',
'next/dist/next-server/server/utils.js'
])

// When a file requires another one, we apply the top-level logic recursively
const getLocalImportDependencies = async function(dependency, basedir, packageJson, state) {
const getTreeShakedDependencies = async function(dependency, basedir, packageJson, state) {
const dependencyPath = await resolvePathPreserveSymlinks(dependency, basedir)
const depsPath = await getFileDependencies(dependencyPath, packageJson, state)
return [dependencyPath, ...depsPath]
}

// When a file requires a module, we find its path inside `node_modules` and
// use all its published files. We also recurse on the module's dependencies.
const getModuleDependencies = async function(dependency, basedir, state, packageJson) {
const getAllDependencies = async function(dependency, basedir, state, packageJson) {
const moduleName = getModuleName(dependency)

// Happens when doing require("@scope") (not "@scope/name") or other oddities
Expand Down Expand Up @@ -150,11 +189,11 @@ const getModuleNameDependencies = async function(moduleName, basedir, state) {

const modulePath = dirname(packagePath)

if (state.modulePaths.includes(modulePath)) {
if (state.modulePaths.has(modulePath)) {
return []
}

state.modulePaths.push(modulePath)
state.modulePaths.add(modulePath)

const pkg = require(packagePath)

Expand Down Expand Up @@ -223,7 +262,7 @@ const getNestedModules = async function(modulePath, state, pkg) {
const dependencies = getNestedDependencies(pkg)

const depsPaths = await Promise.all(
dependencies.map(dependency => getModuleDependencies(dependency, modulePath, state, pkg))
dependencies.map(dependency => getAllDependencies(dependency, modulePath, state, pkg))
)
return [].concat(...depsPaths)
}
Expand Down

0 comments on commit 8756520

Please sign in to comment.