Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
vite-plugin-entry-shaking
Advanced tools
Mimic tree-shaking behaviour when importing code from an entry file in development mode.
Mimic tree-shaking behaviour when importing code from an entry file in development mode.
[!NOTE] The main execution logic of this plugin only applies to development mode because it addresses an issue which is specific to development mode. It may be used in test environments that rely on Vite (e.g. Vitest) but should be used with caution as stated in limitations.
# Using npm
npm i -D vite vite-plugin-entry-shaking
# Using Yarn
yarn add -D vite vite-plugin-entry-shaking
# Using pnpm
pnpm add -D vite vite-plugin-entry-shaking
Setup the plugin in your Vite configuration file.
import { resolve } from 'path';
import { defineConfig } from 'vite';
import EntryShakingPlugin from 'vite-plugin-entry-shaking';
export default defineConfig({
plugins: [
EntryShakingPlugin({
targets: [
// Using direct paths.
resolve(__dirname, 'src/entry-a'),
// Or using glob patterns.
{
glob: 'src/utils/*.ts',
globOptions: { ignore: ['excluded.ts'] },
}
],
}),
],
});
Option name | Type | Default | Description |
---|---|---|---|
targets (required) |
| N/A | You need to list all of the entry points you want this plugin to process. |
extensions | string[] | ['js', 'jsx', 'mjs', 'ts', 'tsx', 'mts'] | This specifies which file extensions you want this plugin to process. |
ignorePatterns | (string | RegExp)[] | [/node_modules/] | This specifies RegExp/string whose matched paths must be ignored by the plugin. |
maxWildcardDepth | number | 0 | How deep should this plugin run static analysis when encountering wildcards? |
diagnostics | boolean | DiagnosticsConfig | true | Toggles all diagnostics when set as a boolean, or specific diagnostics when set as an object. |
debug | boolean | false | Toggles debug mode. This will print debug logs if Vite's logLevel is set to any other value than 'silent' |
Diagnostics are recommendations/warnings emitted by the plugin as it analyzes the specified entry files. They aim to help you improve the plugin's efficiency by suggesting changes and provide explanation on why they were emitted. See RESOURCES for a more in-depth insight about possible diagnostics.
Name | Default | Description |
---|---|---|
definedWithinEntry | true | Emit warning if an entry file defines code that may prevent tree-shaking. |
maxDepthReached | true | Emits a warning when max analysis depth was reached when handling wildcard imports. |
Examples illustrating usage and benefits can be found here. Feel free to fork and play around. For instance, you can toggle the plugin on and off their respective vite config file while serving in development mode and see how it affects the amount of requests made by your browser.
This repository provides a simple CLI to help you quickly scaffold a new example, simply run the following command from the project's root to get started:
pnpm generate-example
Version 0.4.0
introduces
a debugger
as an optional dependency. When installed and attached to the plugin, a debugger application will
open alongside your actual application in dev mode. This can help you get an overall idea of what
the plugin is processing and its impacts on performances.
[!NOTE] This requires installing
vite-plugin-entry-shaking-debugger
and setting thedebug
option totrue
.
The problem this plugin tries to address is well described by this Vite's github issue, so we'll stick to its author's example. Suppose your codebase contains an index file which is basically used as an entry point to dispatch code imported from other files. This is a rather common pattern which may be handy and avoid writing a lot of individual import statements:
// shared/index.ts
export { a } from './a';
export { b } from './b';
export { c } from './c';
Let's pretend you have a module which imports c
from that entry point:
// module.ts
import { c } from './shared';
In development mode, when Vite serves the module.ts
file, the browser loads the shared/index.ts
file which initiates requests for all of the three a
, b
and c
modules it relies on. The thing
is, we actually only needed the c
module, this results in both a
and b
requests being
unnecessary!
As your projet and entry points grow, you end up paying the price for the ever-increasing amount of unnecessary requests and HMR updates, which consumes time and resources. Well, that escalated quickly. Let's try to work around this…
The main idea is to rewrite imports from a target entry point and replace them by individual imports of the actual module. Back with the above example:
// module.ts
import { c } from './shared';
// gets rewritten as…
import { c } from './shared/c';
This way, the shared/index.ts
file is not loaded by the browser anymore and no additional requests
are initiated.
First of all, the plugin reads all of the target entry files listed in the plugin's targets
option. For each entry file :
es-module-lexer
to get a list of
imports and exports.Whenever Vite serves a file which includes an import which resolved to one of the targets
, this
file is transformed to rewrite the relevant import statements. It extracts the list of entities
imported from that entry file, and for each imported entity :
When encountering the above latest case, we have the browser still loading the shared/index.ts
,
which could therefore trigger unnecessary requests, as described earlier. To prevent this kind of
scenario, any import of an entry point is caught and is forced to serve its mutated version we
stored while parsing the entry point file. This ensures the entry point only imports what it needs
to make the code it explicitly defines work.
Please refer to RESOURCES.md for a more precise overview of what happens under the hood.
See es-module-lexer
's
own limitations.
Import statements are not cleaned up from analyzed targets. This means if you import code that was defined within a target, you might still load unnecessary modules. This is by design because getting rid of unused imports would require us to traverse each target's AST to make sure it is indeed not used, which would end up quite expensive.
By default, tree-shaking wildcard imports only work when imported path is part of target list.
Other wildcard imports may be handled by setting the maxWildcardDepth
option.
Read more
You should not expect errors using these. Instead, it just means the content they intend to import won't be tree-shaken by the plugin:
import json from './json.json' assert { type: 'json' }
As a Vite user, you may be using a test runner that relies on Vite's dev server and your usual vite.config
file. Vitest, for example, would - by default - still use this plugin when running tests. This means tested/imported modules and even test files themselves may be transformed. This could be an issue when some of your tests rely on mocks whose references are affected by this plugin (read more on this).
To properly benefit from this plugin within test files, one have to understand how the plugin behaves, how vite's resolver behaves and have a clear overview of their codebase.
Unless you're confident about the above statement, it is recommended to disable this plugin when running tests.
[!WARNING] This feature is still experimental
This plugin supports JSX and TSX syntaxes by pre-transforming them using esbuild
which is included by Vite.
FAQs
Mimic tree-shaking behaviour when importing code from an entry file in development mode.
We found that vite-plugin-entry-shaking demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.