Socket
Socket
Sign inDemoInstall

vite

Package Overview
Dependencies
374
Maintainers
1
Versions
551
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.12.0 to 0.13.0

dist/server/serverPluginAssets.d.ts

13

CHANGELOG.md

@@ -0,1 +1,14 @@

# [0.13.0](https://github.com/vuejs/vite/compare/v0.12.0...v0.13.0) (2020-05-08)
### Features
* **hmr:** change hmr API path to `vite/hmr` and provide typing ([eab49a4](https://github.com/vuejs/vite/commit/eab49a4b7dd7e3bb0ff215c7e7937814cd63bb4f)), closes [#92](https://github.com/vuejs/vite/issues/92)
* cli help message ([a882aa4](https://github.com/vuejs/vite/commit/a882aa48cb447ec3b84019a2ce838ee75d848555))
* **hmr:** support hot.dispose ([e5cf447](https://github.com/vuejs/vite/commit/e5cf447762c73aafd686a69a8b0d8e24c4e00048))
* support --debug flag from cli ([12a5d47](https://github.com/vuejs/vite/commit/12a5d47b2bf2cb7e1badae2e2ee1129c0ae29fe5))
* support asset path import from js + special treatment of /public dir ([9061e44](https://github.com/vuejs/vite/commit/9061e442a7de8f94ca2931299450464f78f82148))
# [0.12.0](https://github.com/vuejs/vite/compare/v0.11.5...v0.12.0) (2020-05-07)

@@ -2,0 +15,0 @@

10

dist/build/buildPluginAsset.d.ts
/// <reference types="node" />
import { Plugin, OutputBundle } from 'rollup';
interface AssetCacheEntry {
content: Buffer;
fileName: string;
content: Buffer | null;
fileName: string | null;
url: string;
}
export declare const resolveAsset: (id: string, publicBase: string, assetsDir: string, inlineLimit: number) => Promise<AssetCacheEntry>;
export declare const registerAssets: (assets: Map<string, string>, bundle: OutputBundle) => void;
export declare const createBuildAssetPlugin: (publicBase: string, assetsDir: string, inlineLimit: number) => Plugin;
export declare const resolveAsset: (id: string, root: string, publicBase: string, assetsDir: string, inlineLimit: number) => Promise<AssetCacheEntry>;
export declare const registerAssets: (assets: Map<string, Buffer>, bundle: OutputBundle) => void;
export declare const createBuildAssetPlugin: (root: string, publicBase: string, assetsDir: string, inlineLimit: number) => Plugin;
export {};

@@ -14,3 +14,3 @@ "use strict";

const assetResolveCache = new Map();
exports.resolveAsset = async (id, publicBase, assetsDir, inlineLimit) => {
exports.resolveAsset = async (id, root, publicBase, assetsDir, inlineLimit) => {
const cached = assetResolveCache.get(id);

@@ -20,15 +20,28 @@ if (cached) {

}
const ext = path_1.default.extname(id);
const baseName = path_1.default.basename(id, ext);
const resolvedFileName = `${baseName}.${hash_sum_1.default(id)}${ext}`;
let url = slash_1.default(path_1.default.join(publicBase, assetsDir, resolvedFileName));
const content = await fs_extra_1.default.readFile(id);
if (!id.endsWith(`.svg`) && content.length < inlineLimit) {
url = `data:${mime_types_1.default.lookup(id)};base64,${content.toString('base64')}`;
let resolved;
const pathFromRoot = path_1.default.relative(root, id);
if (/^public(\/|\\)/.test(pathFromRoot)) {
// assets inside the public directory will be copied over verbatim
// so all we need to do is just append the baseDir
resolved = {
content: null,
fileName: null,
url: slash_1.default(path_1.default.join(publicBase, pathFromRoot))
};
}
const resolved = {
content,
fileName: resolvedFileName,
url
};
if (!resolved) {
const ext = path_1.default.extname(id);
const baseName = path_1.default.basename(id, ext);
const resolvedFileName = `${baseName}.${hash_sum_1.default(id)}${ext}`;
let url = slash_1.default(path_1.default.join(publicBase, assetsDir, resolvedFileName));
const content = await fs_extra_1.default.readFile(id);
if (!id.endsWith(`.svg`) && content.length < inlineLimit) {
url = `data:${mime_types_1.default.lookup(id)};base64,${content.toString('base64')}`;
}
resolved = {
content,
fileName: resolvedFileName,
url
};
}
assetResolveCache.set(id, resolved);

@@ -47,3 +60,3 @@ return resolved;

};
exports.createBuildAssetPlugin = (publicBase, assetsDir, inlineLimit) => {
exports.createBuildAssetPlugin = (root, publicBase, assetsDir, inlineLimit) => {
const assets = new Map();

@@ -54,4 +67,6 @@ return {

if (utils_1.isStaticAsset(id)) {
const { fileName, content, url } = await exports.resolveAsset(id, publicBase, assetsDir, inlineLimit);
assets.set(fileName, content);
const { fileName, content, url } = await exports.resolveAsset(id, root, publicBase, assetsDir, inlineLimit);
if (fileName && content) {
assets.set(fileName, content);
}
debug(`${id} -> ${url.startsWith('data:') ? `base64 inlined` : url}`);

@@ -58,0 +73,0 @@ return `export default ${JSON.stringify(url)}`;

@@ -27,4 +27,6 @@ "use strict";

const file = path_1.default.join(fileDir, rawUrl);
const { fileName, content, url } = await buildPluginAsset_1.resolveAsset(file, publicBase, assetsDir, inlineLimit);
assets.set(fileName, content);
const { fileName, content, url } = await buildPluginAsset_1.resolveAsset(file, root, publicBase, assetsDir, inlineLimit);
if (fileName && content) {
assets.set(fileName, content);
}
debug(`url(${rawUrl}) -> ${url.startsWith('data:') ? `base64 inlined` : `url(${url})`}`);

@@ -31,0 +33,0 @@ return `${before}${url}${after}`;

import { Plugin } from 'rollup';
import { InternalResolver } from '../resolver';
export declare const createBuildHtmlPlugin: (indexPath: string | null, publicBasePath: string, assetsDir: string, inlineLimit: number, resolver: InternalResolver) => Promise<{
export declare const createBuildHtmlPlugin: (root: string, indexPath: string | null, publicBasePath: string, assetsDir: string, inlineLimit: number, resolver: InternalResolver) => Promise<{
renderIndex: (...args: any[]) => string;
htmlPlugin: null;
} | {
renderIndex: (root: string, cdn: boolean, cssFileName: string, bundleOutput: [import("rollup").OutputChunk, ...(import("rollup").OutputAsset | import("rollup").OutputChunk)[]]) => string;
renderIndex: (root: string, cssFileName: string, bundleOutput: [import("rollup").OutputChunk, ...(import("rollup").OutputAsset | import("rollup").OutputChunk)[]]) => string;
htmlPlugin: Plugin;
}>;

@@ -9,7 +9,6 @@ "use strict";

const pathUtils_1 = require("../utils/pathUtils");
const resolveVue_1 = require("../utils/resolveVue");
const buildPluginAsset_1 = require("./buildPluginAsset");
const compiler_dom_1 = require("@vue/compiler-dom");
const magic_string_1 = __importDefault(require("magic-string"));
exports.createBuildHtmlPlugin = async (indexPath, publicBasePath, assetsDir, inlineLimit, resolver) => {
exports.createBuildHtmlPlugin = async (root, indexPath, publicBasePath, assetsDir, inlineLimit, resolver) => {
if (!indexPath || !(await fs_extra_1.default.pathExists(indexPath))) {

@@ -22,3 +21,3 @@ return {

const rawHtml = await fs_extra_1.default.readFile(indexPath, 'utf-8');
let { html: processedHtml, js } = await compileHtml(rawHtml, publicBasePath, assetsDir, inlineLimit, resolver);
let { html: processedHtml, js } = await compileHtml(root, rawHtml, publicBasePath, assetsDir, inlineLimit, resolver);
const htmlPlugin = {

@@ -53,9 +52,5 @@ name: 'vite:html',

};
const renderIndex = (root, cdn, cssFileName, bundleOutput) => {
const renderIndex = (root, cssFileName, bundleOutput) => {
// inject css link
processedHtml = injectCSS(processedHtml, cssFileName);
// if not inlining vue, inject cdn link so it can start the fetch early
if (cdn) {
processedHtml = injectScript(processedHtml, resolveVue_1.resolveVue(root).cdnLink);
}
// inject js entry chunks

@@ -85,3 +80,3 @@ for (const chunk of bundleOutput) {

// and scripts
const compileHtml = async (html, publicBasePath, assetsDir, inlineLimit, resolver) => {
const compileHtml = async (root, html, publicBasePath, assetsDir, inlineLimit, resolver) => {
const ast = compiler_dom_1.parse(html);

@@ -91,3 +86,3 @@ let js = '';

const assetUrls = [];
const viteHtmlTrasnfrom = (node, context) => {
const viteHtmlTrasnfrom = (node) => {
if (node.type === 1 /* ELEMENT */) {

@@ -139,3 +134,3 @@ if (node.tag === 'script') {

const value = attr.value;
const { url } = await buildPluginAsset_1.resolveAsset(resolver.requestToFile(value.content), publicBasePath, assetsDir, inlineLimit);
const { url } = await buildPluginAsset_1.resolveAsset(resolver.requestToFile(value.content), root, publicBasePath, assetsDir, inlineLimit);
s.overwrite(value.loc.start.offset, value.loc.end.offset, url);

@@ -142,0 +137,0 @@ }

import { Plugin } from 'rollup';
import { InternalResolver } from '../resolver';
export declare const createBuildResolvePlugin: (root: string, cdn: boolean, resolver: InternalResolver) => Plugin;
export declare const createBuildResolvePlugin: (root: string, resolver: InternalResolver) => Plugin;

@@ -11,3 +11,3 @@ "use strict";

const debug = require('debug')('vite:build:resolve');
exports.createBuildResolvePlugin = (root, cdn, resolver) => {
exports.createBuildResolvePlugin = (root, resolver) => {
return {

@@ -28,9 +28,3 @@ name: 'vite:resolve',

const vuePaths = resolveVue_1.resolveVue(root);
if (id === 'vue' && cdn) {
return {
id: vuePaths.cdnLink,
external: true
};
}
else if (id in vuePaths) {
if (id in vuePaths) {
return vuePaths[id];

@@ -56,3 +50,3 @@ }

if (id === serverPluginHmr_1.hmrClientId) {
return `export const hot = {accept(){},on(){}}`;
return `export const hot = {accept(){},dispose(){},on(){}}`;
}

@@ -59,0 +53,0 @@ }

@@ -6,7 +6,2 @@ import { InputOptions, OutputOptions, RollupOutput } from 'rollup';

/**
* Project root path on file system.
* Defaults to `process.cwd()`
*/
root?: string;
/**
* Base public path when served in production.

@@ -17,12 +12,2 @@ * Defaults to /

/**
* If true, will be importing Vue from a CDN.
* Dsiabled automatically when a local vue installation is present.
*/
cdn?: boolean;
/**
* Resolvers to map dev server public path requests to/from file system paths,
* and optionally map module ids to public path requests.
*/
resolvers?: Resolver[];
/**
* Defaults to `dist`

@@ -43,2 +28,27 @@ */

/**
* Whether to generate sourcemap
*/
sourcemap?: boolean;
/**
* Whether to minify output
*/
minify?: boolean | 'terser' | 'esbuild';
/**
* Configure what to use for jsx factory and fragment
*/
jsx?: {
factory?: string;
fragment?: string;
};
/**
* Project root path on file system.
* Defaults to `process.cwd()`
*/
root?: string;
/**
* Resolvers to map dev server public path requests to/from file system paths,
* and optionally map module ids to public path requests.
*/
resolvers?: Resolver[];
/**
* Will be passed to rollup.rollup()

@@ -59,9 +69,10 @@ * https://rollupjs.org/guide/en/#big-list-of-options

/**
* Configure what to use for jsx factory and fragment
* Whether to log asset info to console
*/
jsx?: {
factory?: string;
fragment?: string;
};
silent?: boolean;
/**
* Whether to write bundle to disk
*/
write?: boolean;
/**
* Whether to emit index.html

@@ -74,18 +85,2 @@ */

emitAssets?: boolean;
/**
* Whether to generate sourcemap
*/
sourcemap?: boolean;
/**
* Whether to write bundle to disk
*/
write?: boolean;
/**
* Whether to minify output
*/
minify?: boolean | 'terser' | 'esbuild';
/**
* Whether to log asset info to console
*/
silent?: boolean;
}

@@ -92,0 +87,0 @@ export interface BuildResult {

@@ -8,3 +8,2 @@ "use strict";

const fs_extra_1 = __importDefault(require("fs-extra"));
const resolveVue_1 = require("../utils/resolveVue");
const resolve_from_1 = __importDefault(require("resolve-from"));

@@ -34,3 +33,3 @@ const chalk_1 = __importDefault(require("chalk"));

const start = Date.now();
const { root = process.cwd(), base = '/', cdn = !resolveVue_1.resolveVue(root).isLocal, outDir = path_1.default.resolve(root, 'dist'), assetsDir = 'assets', assetsInlineLimit = 4096, resolvers = [], rollupInputOptions = {}, rollupOutputOptions = {}, rollupPluginVueOptions = {}, jsx = {}, emitIndex = true, emitAssets = true, write = true, minify = true, silent = false, sourcemap = false } = options;
const { root = process.cwd(), base = '/', outDir = path_1.default.resolve(root, 'dist'), assetsDir = 'assets', assetsInlineLimit = 4096, resolvers = [], rollupInputOptions = {}, rollupOutputOptions = {}, rollupPluginVueOptions = {}, jsx = {}, emitIndex = true, emitAssets = true, write = true, minify = true, silent = false, sourcemap = false } = options;
const indexPath = emitIndex ? path_1.default.resolve(root, 'index.html') : null;

@@ -41,3 +40,3 @@ const publicBasePath = base.replace(/([^/])$/, '$1/'); // ensure ending slash

const resolver = resolver_1.createResolver(root, resolvers);
const { htmlPlugin, renderIndex } = await buildPluginHtml_1.createBuildHtmlPlugin(indexPath, publicBasePath, assetsDir, assetsInlineLimit, resolver);
const { htmlPlugin, renderIndex } = await buildPluginHtml_1.createBuildHtmlPlugin(root, indexPath, publicBasePath, assetsDir, assetsInlineLimit, resolver);
// lazy require rollup so that we don't load it when only using the dev server

@@ -54,3 +53,3 @@ // importing it just for the types

// vite:resolve
buildPluginResolve_1.createBuildResolvePlugin(root, cdn, resolver),
buildPluginResolve_1.createBuildResolvePlugin(root, resolver),
// vite:html

@@ -86,3 +85,3 @@ ...(htmlPlugin ? [htmlPlugin] : []),

// vite:asset
buildPluginAsset_1.createBuildAssetPlugin(publicBasePath, assetsDir, assetsInlineLimit),
buildPluginAsset_1.createBuildAssetPlugin(root, publicBasePath, assetsDir, assetsInlineLimit),
// minify with terser

@@ -107,3 +106,3 @@ // this is the default which has better compression, but slow

});
const indexHtml = renderIndex(root, cdn, cssFileName, output);
const indexHtml = renderIndex(root, cssFileName, output);
if (write) {

@@ -120,2 +119,3 @@ const cwd = process.cwd();

await fs_extra_1.default.ensureDir(outDir);
// write js chunks and assets
for (const chunk of output) {

@@ -144,2 +144,7 @@ if (chunk.type === 'chunk') {

}
// copy over /public if it exists
const publicDir = path_1.default.resolve(root, 'public');
if (await fs_extra_1.default.pathExists(publicDir)) {
await fs_extra_1.default.copy(publicDir, path_1.default.resolve(outDir, 'public'));
}
}

@@ -146,0 +151,0 @@ if (!silent) {

@@ -6,53 +6,86 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const os_1 = __importDefault(require("os"));
const chalk_1 = __importDefault(require("chalk"));
const os_1 = require("os");
console.log(chalk_1.default.cyan(`vite v${require('../package.json').version}`));
const s = Date.now();
const argv = require('minimist')(process.argv.slice(2));
if (argv.help) {
// TODO print supported args on --help
const args = parseArgs();
if (args.help || args.h) {
logHelp();
}
Object.keys(argv).forEach((key) => {
// cast xxx=false into actual `false`
if (argv[key] === 'false') {
argv[key] = false;
else if (args.version || args.v) {
// noop
}
else if (!args.command || args.command === 'serve') {
runServe(args);
}
else if (args.command === 'build') {
runBuild(args);
}
else if (args.command === 'optimize') {
// runOptimize()
}
else {
console.error(chalk_1.default.red(`unknown command: ${args.command}`));
process.exit(1);
}
function parseArgs() {
const argv = require('minimist')(process.argv.slice(2));
// convert debug flag
if (argv.debug) {
process.env.DEBUG = `vite:` + (argv.debug === true ? '*' : argv.debug);
}
// map jsx args
if (key === 'jsx-factory') {
if (argv['jsx-factory']) {
;
(argv.jsx || (argv.jsx = {})).factory = argv[key];
(argv.jsx || (argv.jsx = {})).factory = argv['jsx-factory'];
}
if (key === 'jsx-fragment') {
if (argv['jsx-fragment']) {
;
(argv.jsx || (argv.jsx = {})).fragment = argv[key];
(argv.jsx || (argv.jsx = {})).fragment = argv['jsx-fragment'];
}
});
if (argv._[0] === 'build') {
let spinner;
const msg = 'Building for production...';
if (process.env.DEBUG || process.env.NODE_ENV === 'test') {
console.log(msg);
// cast xxx=false into actual `false`
Object.keys(argv).forEach((key) => {
if (argv[key] === 'false') {
argv[key] = false;
}
});
// command
if (argv._[0]) {
argv.command = argv._[0];
}
else {
spinner = require('ora')(msg + '\n').start();
// normalize root
// assumes all commands are in the form of `vite [command] [root]`
if (argv._[1] && !argv.root) {
argv.root = argv._[1];
}
require('../dist')
.build({
...argv,
cdn: argv.cdn === 'false' ? false : argv.cdn
})
.then(() => {
spinner && spinner.stop();
process.exit(0);
})
.catch((err) => {
spinner && spinner.stop();
console.error(chalk_1.default.red(`[vite] Build errored out.`));
console.error(err);
process.exit(1);
});
return argv;
}
else {
const server = require('../dist').createServer(argv);
let port = argv.port || 3000;
function logHelp() {
console.log(`
Usage: vite [command] [args] [--options]
Commands:
vite Start server in current directory.
vite serve [root=cwd] Start server in target directory.
vite build [root=cwd] Build target directory.
Options:
--help, -h [boolean] show help
--version, -v [boolean] show version
--port [number] port to use for serve
--open [boolean] open browser on server start
--base [string] public base path for build (default: /)
--outDir [string] output directory for build (default: dist)
--assetsDir [string] directory under outDir to place assets in (default: assets)
--assetsInlineLimit [number] static asset base64 inline threshold in bytes (default: 4096)
--sourcemap [boolean] output source maps for build (default: false)
--minify [boolean | 'terser' | 'esbuild'] disable minification, or specify
minifier to use. (default: 'terser')
--jsx-factory [string] (default: React.createElement)
--jsx-fragment [string] (default: React.Fragment)
`);
}
function runServe(args) {
const server = require('../dist').createServer(args);
let port = args.port || 3000;
server.on('error', (e) => {

@@ -71,26 +104,39 @@ if (e.code === 'EADDRINUSE') {

});
server.on('listening', () => {
server.listen(port, () => {
console.log(`Dev server running at:`);
const addresses = getIPv4AddressList();
addresses.forEach((ip) => {
console.log(` > http://${ip}:${port}`);
const interfaces = os_1.default.networkInterfaces();
Object.keys(interfaces).forEach((key) => {
;
(interfaces[key] || [])
.filter((details) => details.family === 'IPv4')
.map((detail) => detail.address.replace('127.0.0.1', 'localhost'))
.forEach((ip) => console.log(` > http://${ip}:${port}`));
});
console.log();
require('debug')('vite:server')(`server ready in ${Date.now() - s}ms.`);
if (argv.open) {
require('./utils/openBrowser').openBrowser(`http://${addresses[0]}:${port}`);
if (args.open) {
require('./utils/openBrowser').openBrowser(`http://localhost:${port}`);
}
});
server.listen(port);
}
function getIPv4AddressList() {
const interfaces = os_1.networkInterfaces();
let result = [];
Object.keys(interfaces).forEach((key) => {
const ips = (interfaces[key] || [])
.filter((details) => details.family === 'IPv4')
.map((detail) => detail.address.replace('127.0.0.1', 'localhost'));
result = result.concat(ips);
});
return result;
async function runBuild(args) {
let spinner;
const msg = 'Building for production...';
if (process.env.DEBUG || process.env.NODE_ENV === 'test') {
console.log(msg);
}
else {
spinner = require('ora')(msg + '\n').start();
}
try {
await require('../dist').build(args);
spinner && spinner.stop();
process.exit(0);
}
catch (err) {
spinner && spinner.stop();
console.error(chalk_1.default.red(`[vite] Build errored out.`));
console.error(err);
process.exit(1);
}
}
export declare function updateStyle(id: string, url: string): void;
export declare const hot: {
accept(importer: string, deps: string | string[], callback?: (modules: object | object[]) => void): void;
accept(id: string, deps: string | string[], callback?: (modules: object | object[]) => void): void;
dispose(id: string, cb: () => void): void;
on(event: string, cb: () => void): void;
};

@@ -79,10 +79,18 @@ console.log('[vite] connecting...');

const jsUpdateMap = new Map();
const jsDisposeMap = new Map();
const customUpdateMap = new Map();
export const hot = {
accept(importer, deps, callback = () => { }) {
jsUpdateMap.set(importer, (timestamp) => {
accept(id, deps, callback = () => { }) {
jsUpdateMap.set(id, async (timestamp) => {
if (Array.isArray(deps)) {
for (const id of deps) {
const disposer = jsDisposeMap.get(id);
if (disposer)
await disposer();
}
Promise.all(deps.map((dep) => import(dep + `?t=${timestamp}`))).then(callback);
}
else {
const disposer = jsDisposeMap.get(deps);
disposer && (await disposer());
import(deps + `?t=${timestamp}`).then(callback);

@@ -92,2 +100,5 @@ }

},
dispose(id, cb) {
jsDisposeMap.set(id, cb);
},
on(event, cb) {

@@ -94,0 +105,0 @@ const exisitng = customUpdateMap.get(event) || [];

@@ -17,4 +17,6 @@ "use strict";

const serverPluginCss_1 = require("./serverPluginCss");
const serverPluginAssets_1 = require("./serverPluginAssets");
const serverPluginEsbuild_1 = require("./serverPluginEsbuild");
const internalPlugins = [
serverPluginHmr_1.hmrPlugin,
serverPluginModuleRewrite_1.moduleRewritePlugin,

@@ -26,3 +28,3 @@ serverPluginModuleResolve_1.moduleResolvePlugin,

serverPluginCss_1.cssPlugin,
serverPluginHmr_1.hmrPlugin,
serverPluginAssets_1.assetPathPlugin,
serverPluginServeStatic_1.serveStaticPlugin

@@ -29,0 +31,0 @@ ];

@@ -15,3 +15,3 @@ import { Plugin } from '.';

export declare const hmrClientFilePath: string;
export declare const hmrClientId = "@hmr";
export declare const hmrClientId = "vite/hmr";
export declare const hmrClientPublicPath: string;

@@ -18,0 +18,0 @@ interface HMRPayload {

@@ -13,3 +13,3 @@ "use strict";

// boundary is either a `.vue` file or a `.js` file that explicitly indicated
// that it accepts hot updates (by importing from the `/@hmr` special module)
// that it accepts hot updates (by importing from the `/vite/hmr` special module)
// 5. If any parent chain exhausts without ever running into an HMR boundary,

@@ -42,3 +42,3 @@ // it's considered a "dead end". This causes a full page reload.

exports.hmrClientFilePath = path_1.default.resolve(__dirname, '../client.js');
exports.hmrClientId = '@hmr';
exports.hmrClientId = 'vite/hmr';
exports.hmrClientPublicPath = `/${exports.hmrClientId}`;

@@ -280,40 +280,47 @@ exports.hmrPlugin = ({ root, app, server, watcher, resolver }) => {

};
const checkAcceptCall = (node, isTopLevel = false) => {
const checkHotCall = (node, isTopLevel = false) => {
if (node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'hot' &&
node.callee.property.name === 'accept') {
node.callee.object.name === 'hot') {
if (isTopLevel) {
console.warn(chalk_1.default.yellow(`[vite warn] hot.accept() in ${importer} should be wrapped in ` +
console.warn(chalk_1.default.yellow(`[vite warn] HMR API calls in ${importer} should be wrapped in ` +
`\`if (__DEV__) {}\` conditional blocks so that they can be ` +
`tree-shaken in production.`));
`tree-shaken in production.`)
// TODO generateCodeFrame
);
}
const args = node.arguments;
// inject the imports's own path so it becomes
// hot.accept('/foo.js', ['./bar.js'], () => {})
s.appendLeft(args[0].start, JSON.stringify(importer) + ', ');
// register the accepted deps
if (args[0].type === 'ArrayExpression') {
args[0].elements.forEach((e) => {
if (e && e.type !== 'StringLiteral') {
console.error(`[vite] HMR syntax error in ${importer}: hot.accept() deps list can only contain string literals.`);
}
else if (e) {
registerDep(e);
}
});
}
else if (args[0].type === 'StringLiteral') {
registerDep(args[0]);
}
else if (args[0].type.endsWith('FunctionExpression')) {
// self accepting, rewrite to inject itself
// hot.accept(() => {}) --> hot.accept('/foo.js', '/foo.js', () => {})
if (node.callee.property.name === 'accept') {
const args = node.arguments;
// inject the imports's own path so it becomes
// hot.accept('/foo.js', ['./bar.js'], () => {})
s.appendLeft(args[0].start, JSON.stringify(importer) + ', ');
ensureMapEntry(exports.hmrAcceptanceMap, importer).add(importer);
// register the accepted deps
if (args[0].type === 'ArrayExpression') {
args[0].elements.forEach((e) => {
if (e && e.type !== 'StringLiteral') {
console.error(`[vite] HMR syntax error in ${importer}: hot.accept() deps list can only contain string literals.`);
}
else if (e) {
registerDep(e);
}
});
}
else if (args[0].type === 'StringLiteral') {
registerDep(args[0]);
}
else if (args[0].type.endsWith('FunctionExpression')) {
// self accepting, rewrite to inject itself
// hot.accept(() => {}) --> hot.accept('/foo.js', '/foo.js', () => {})
s.appendLeft(args[0].start, JSON.stringify(importer) + ', ');
ensureMapEntry(exports.hmrAcceptanceMap, importer).add(importer);
}
else {
console.error(`[vite] HMR syntax error in ${importer}: ` +
`hot.accept() expects a dep string, an array of deps, or a callback.`);
}
}
else {
console.error(`[vite] HMR syntax error in ${importer}: ` +
`hot.accept() expects a dep string, an array of deps, or a callback.`);
if (node.callee.property.name === 'dispose') {
// inject the imports's own path to dispose calls as well
s.appendLeft(node.arguments[0].start, JSON.stringify(importer) + ', ');
}

@@ -325,3 +332,3 @@ }

// top level hot.accept() call
checkAcceptCall(node.expression, isTopLevel);
checkHotCall(node.expression, isTopLevel);
// __DEV__ && hot.accept()

@@ -332,3 +339,3 @@ if (node.expression.type === 'LogicalExpression' &&

node.expression.left.name === '__DEV__') {
checkAcceptCall(node.expression.right);
checkHotCall(node.expression.right);
}

@@ -344,3 +351,3 @@ }

if (node.consequent.type === 'ExpressionStatement') {
checkAcceptCall(node.consequent.expression);
checkHotCall(node.consequent.expression);
}

@@ -347,0 +354,0 @@ }

@@ -81,3 +81,3 @@ "use strict";

// skip internal client
!ctx.path.startsWith(`/@hmr`) &&
!ctx.path.startsWith(serverPluginHmr_1.hmrClientPublicPath) &&
// only need to rewrite for <script> part in vue files

@@ -128,9 +128,8 @@ !((ctx.path.endsWith('.vue') || ctx.vue) && ctx.query.type != null)) {

if (utils_1.isExternalUrl(id)) {
break;
continue;
}
let resolved;
if (/^[^\/\.]/.test(id)) {
resolved = resolver.idToRequest(id) || `/@modules/${id}`;
if (resolved === serverPluginHmr_1.hmrClientPublicPath &&
!/.vue$|.vue\?type=/.test(importer)) {
if (id === serverPluginHmr_1.hmrClientId) {
resolved = serverPluginHmr_1.hmrClientPublicPath;
if (!/.vue$|.vue\?type=/.test(importer)) {
// the user explicit imports the HMR API in a js file

@@ -143,2 +142,5 @@ // making the module hot.

}
else if (/^[^\/\.]/.test(id)) {
resolved = resolver.idToRequest(id) || `/@modules/${id}`;
}
else {

@@ -145,0 +147,0 @@ let { pathname, query } = utils_1.resolveRelativeRequest(importer, id);

@@ -17,6 +17,5 @@ import { Context } from 'koa';

* Check if a request is an import from js (instead of fetch() or ajax requests)
* A request qualifies as long as it's not from page (no ext or .html).
* this is because non-js files can be transformed into js and import json
* as well.
* A request qualifies as long as it's from one of the supported js source file
* formats (vue,js,ts,jsx,tsx)
*/
export declare const isImportRequest: (ctx: Context) => boolean;

@@ -31,11 +31,16 @@ "use strict";

};
const timeStampRE = /(&|\?)t=\d+/;
const jsSrcFileRE = /\.(vue|jsx?|tsx?)$/;
/**
* Check if a request is an import from js (instead of fetch() or ajax requests)
* A request qualifies as long as it's not from page (no ext or .html).
* this is because non-js files can be transformed into js and import json
* as well.
* A request qualifies as long as it's from one of the supported js source file
* formats (vue,js,ts,jsx,tsx)
*/
exports.isImportRequest = (ctx) => {
const referer = exports.cleanUrl(ctx.get('referer'));
return /\.\w+$/.test(referer) && !referer.endsWith('.html');
if (!ctx.accepts('js')) {
return false;
}
// strip HMR timestamps
const referer = ctx.get('referer').replace(timeStampRE, '');
return jsSrcFileRE.test(referer);
};

@@ -11,3 +11,2 @@ import sfcCompiler from '@vue/compiler-sfc';

isLocal: boolean;
cdnLink: string;
}

@@ -14,0 +13,0 @@ export declare function resolveVue(root: string): ResolvedVuePaths;

@@ -60,4 +60,3 @@ "use strict";

compiler: compilerPath,
isLocal,
cdnLink: `https://unpkg.com/vue@${vueVersion}/dist/vue.esm-browser.prod.js`
isLocal
};

@@ -64,0 +63,0 @@ return resolved;

{
"name": "vite",
"version": "0.12.0",
"version": "0.13.0",
"license": "MIT",

@@ -13,3 +13,4 @@ "author": "Evan You",

"bin",
"dist"
"dist",
"hmr.d.ts"
],

@@ -33,3 +34,3 @@ "engines": {

"lint": "prettier --write --parser typescript \"src/**/*.ts\"",
"test": "jest --runInBand",
"test": "jest --clearCache && jest --runInBand",
"windows-ci": "yarn build && jest --runInBand --forceExit",

@@ -36,0 +37,0 @@ "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",

# vite ⚡
> No-bundle Dev Server for Vue 3 Single-File Components.
> Make Web Dev Fast Again
- Super fast cold server start
- Super fast hot module replacement (HMR)
- Lightning fast cold server start
- Instant hot module replacement (HMR)
- True on-demand compilation

@@ -25,3 +25,3 @@ - More details in [How and Why](#how-and-why)

``` bash
```bash
$ yarn create vite-app <project-name>

@@ -35,5 +35,5 @@ $ cd <project-name>

`vite` requires [native ES module imports](https://caniuse.com/#feat=es6-module) during development. The production build also relies on dynamic imports for code-splitting (which can be [polyfilled](https://github.com/GoogleChromeLabs/dynamic-import-polyfill)).
Vite requires [native ES module imports](https://caniuse.com/#feat=es6-module) during development. The production build also relies on dynamic imports for code-splitting (which can be [polyfilled](https://github.com/GoogleChromeLabs/dynamic-import-polyfill)).
`vite` assumes you are targeting modern browsers and therefore does not perform any compatibility-oriented code transforms by default. Technically, you *can* add `autoprefixer` yourself using a PostCSS config file, or add necessary polyfills and post-processing steps to make your code work in legacy browsers - however that is not `vite`'s concern by design.
Vite assumes you are targeting modern browsers and therefore does not perform any compatibility-oriented code transforms by default. Technically, you _can_ add `autoprefixer` yourself using a PostCSS config file, or add necessary polyfills and post-processing steps to make your code work in legacy browsers - however that is not Vite's concern by design.

@@ -53,3 +53,3 @@ ## Features

`vite` tries to mirror the default configuration in [vue-cli](http://cli.vuejs.org/) as much as possible. If you've used `vue-cli` or other webpack-based boilerplates before, you should feel right at home. That said, do expect things to be different here and there.
Vite tries to mirror the default configuration in [vue-cli](http://cli.vuejs.org/) as much as possible. If you've used `vue-cli` or other webpack-based boilerplates before, you should feel right at home. That said, do expect things to be different here and there.

@@ -64,5 +64,5 @@ ### Bare Module Resolving

The above will throw an error by default. `vite` detects such bare module imports in all served `.js` files and rewrites them with special paths like `/@modules/vue`. Under these special paths, `vite` performs module resolution to locate the correct files on disk:
The above will throw an error by default. Vite detects such bare module imports in all served `.js` files and rewrites them with special paths like `/@modules/vue`. Under these special paths, Vite performs module resolution to locate the correct files on disk:
- `vue` has special handling: you don't need to install it since `vite` will serve it by default. But if you want to use a specific version of `vue` (only supports Vue 3.x), you can install `vue` locally into `node_modules` and it will be preferred (`@vue/compiler-sfc` of the same version will also need to be installed).
- `vue` has special handling: you don't need to install it since Vite will serve it by default. But if you want to use a specific version of `vue` (only supports Vue 3.x), you can install `vue` locally into `node_modules` and it will be preferred (`@vue/compiler-sfc` of the same version will also need to be installed).

@@ -81,3 +81,3 @@ - If a `web_modules` directory (generated by [Snowpack](https://www.snowpack.dev/)) is present, we will try to locate it.

import { foo } from './foo.js'
import { hot } from '@hmr'
import { hot } from 'vite/hmr'

@@ -103,3 +103,3 @@ foo()

```js
import { hot } from '@hmr'
import { hot } from 'vite/hmr'

@@ -110,3 +110,3 @@ export const count = 1

if (__DEV__) {
hot.accept(newModule => {
hot.accept((newModule) => {
console.log('updated: count is now ', newModule.count)

@@ -117,4 +117,19 @@ })

Note that `vite`'s HMR does not actually swap the originally imported module: if an accepting module re-exports imports from a dep, then it is responsible for updating those re-exports (and these exports must be using `let`). In addition, importers up the chain from the accepting module will not be notified of the change.
A self-accepting module, or a module that expects to be accepted by others can use `hot.dispose` to cleanup any persistent side effects created by its updated copy:
```js
import { hot } from 'vite/hmr'
function setupSideEffect() {}
function cleanupSideEffect() {}
setupSideEffect()
if (__DEV__) {
hot.dispose(cleanupSideEffect)
}
```
Note that Vite's HMR does not actually swap the originally imported module: if an accepting module re-exports imports from a dep, then it is responsible for updating those re-exports (and these exports must be using `let`). In addition, importers up the chain from the accepting module will not be notified of the change.
This simplified HMR implementation is sufficient for most dev use cases, while allowing us to skip the expensive work of generating proxy modules.

@@ -124,4 +139,6 @@

Starting with v0.11, `vite` supports `<script lang="ts">` in `*.vue` files, and importing `.ts` files out of the box. Note that `vite` does **NOT** perform type checking - it assumes type checking is taken care of by your IDE and build process (you can run `tsc --noEmit` in the build script). With that in mind, `vite` uses [esbuild](https://github.com/evanw/esbuild) to transpile TypeScript into JavaScript which is about 20~30x faster than vanilla `tsc`.
Starting with v0.11, Vite supports `<script lang="ts">` in `*.vue` files, and importing `.ts` files out of the box. Note that Vite does **NOT** perform type checking - it assumes type checking is taken care of by your IDE and build process (you can run `tsc --noEmit` in the build script). With that in mind, Vite uses [esbuild](https://github.com/evanw/esbuild) to transpile TypeScript into JavaScript which is about 20~30x faster than vanilla `tsc`, and HMR updates can reflect in the browser in under 50ms.
Note that because `esbuild` only performs transpilation without type information, it doesn't support certain features like const enum and implicit type-only imports. You must set `"isolatedModules": true` in your `tsconfig.json` under `compilerOptions` so that TS will warn you against the features that do not work with isolated transpilation.
### CSS / JSON Importing

@@ -141,9 +158,11 @@

There is no conventional `public` directory. All referenced assets, including those using absolute paths, will be copied to the dist folder with a hashed file name in the production build. Never-referenced assets will not be copied.
All referenced assets, including those using absolute paths, will be copied to the dist folder with a hashed file name in the production build. Never-referenced assets will not be copied. Similar to `vue-cli`, image assets smaller than 4kb will be base64 inlined.
Similar to `vue-cli`, image assets smaller than 4kb will be base64 inlined.
The exception is the `public` directory - assets placed in this directory will be copied to the dist directory as-is. It can be used to provide assets that are never referenced in your code - e.g. `robots.txt`.
All path references, including absolute paths and those starting with `/public`, should be based on your working directory structure. If you are deploying your project under a nested public path, simply specify `--base=/your/public/path/` and all asset paths will be rewritten accordingly. **You never need to think about the public path during development.**
### PostCSS
`vite` automatically applies your PostCSS config to all styles in `*.vue` files and imported plain `.css` files. Just install necessary plugins and add a `postcss.config.js` in your project root.
Vite automatically applies your PostCSS config to all styles in `*.vue` files and imported plain `.css` files. Just install necessary plugins and add a `postcss.config.js` in your project root.

@@ -156,8 +175,9 @@ ### CSS Modules

Because `vite` targets modern browsers only, it is recommended to use native CSS variables with PostCSS plugins that implement CSSWG drafts (e.g. [postcss-nesting](https://github.com/jonathantneal/postcss-nesting)) and author plain, future-standards-compliant CSS. That said, if you insist on using a CSS pre-processor, you can install the corresponding pre-processor and just use it:
Because Vite targets modern browsers only, it is recommended to use native CSS variables with PostCSS plugins that implement CSSWG drafts (e.g. [postcss-nesting](https://github.com/jonathantneal/postcss-nesting)) and author plain, future-standards-compliant CSS. That said, if you insist on using a CSS pre-processor, you can install the corresponding pre-processor and just use it:
``` bash
```bash
yarn add -D sass
```
``` vue
```vue
<style lang="scss">

@@ -176,11 +196,11 @@ /* use scss */

``` js
```js
import { React, ReactDOM } from 'https://unpkg.com/es-react'
ReactDOM.render(<h1>Hello, what!</h1>, document.getElementById("app"));
ReactDOM.render(<h1>Hello, what!</h1>, document.getElementById('app'))
```
JSX can also be customized via `--jsx-factory` and `--jsx-fragment` flags from the CLI or `jsx: { factory, fragment }` fro the API. For example, to use [Preact](https://preactjs.com/) with `vite`:
JSX can also be customized via `--jsx-factory` and `--jsx-fragment` flags from the CLI or `jsx: { factory, fragment }` fro the API. For example, to use [Preact](https://preactjs.com/) with Vite:
``` json
```json
{

@@ -192,5 +212,6 @@ "scripts": {

```
``` jsx
import { h, render } from "preact"
render(<h1>Hello, what!</h1>, document.getElementById("app"))
```jsx
import { h, render } from 'preact'
render(<h1>Hello, what!</h1>, document.getElementById('app'))
```

@@ -200,3 +221,3 @@

- Vue 3's JSX transform is still WIP, so `vite`'s JSX support currently only targets React/Preact.
- Vue 3's JSX transform is still WIP, so Vite's JSX support currently only targets React/Preact.

@@ -207,3 +228,3 @@ - There is no out-of-the-box HMR when using non-Vue frameworks, but userland HMR support is technically via the server API.

`vite` does utilize bundling for production builds, because native ES module imports result in waterfall network requests that are simply too punishing for page load time in production.
Vite does utilize bundling for production builds, because native ES module imports result in waterfall network requests that are simply too punishing for page load time in production.

@@ -220,3 +241,3 @@ You can run `vite build` to bundle the app.

``` js
```js
const { createServer } = require('vite')

@@ -257,5 +278,3 @@

createServer({
plugins: [
myPlugin
]
plugins: [myPlugin]
}).listen(3000)

@@ -268,3 +287,3 @@ ```

``` js
```js
const { build } = require('vite')

@@ -290,9 +309,7 @@

## How and Why
### How is This Different from `vue-cli` or other Bundler-based Solutions?
### How is This Different from `vue-cli` or Other Bundler-based Solutions?
The primary difference is that for `vite` there is no bundling during development. The ES Import syntax in your source code is served directly to the browser, and the browser parses them via native `<script module>` support, making HTTP requests for each import. The dev server intercepts the requests and performs code transforms if necessary. For example, an import to a `*.vue` file is compiled on the fly right before it's sent back to the browser.
The primary difference is that for Vite there is no bundling during development. The ES Import syntax in your source code is served directly to the browser, and the browser parses them via native `<script module>` support, making HTTP requests for each import. The dev server intercepts the requests and performs code transforms if necessary. For example, an import to a `*.vue` file is compiled on the fly right before it's sent back to the browser.

@@ -309,14 +326,30 @@ There are a few advantages of this approach:

Finally, because compilation is still done in Node, it can technically support any code transforms a bundler can, and nothing prevents you from eventually bundling the code for production. In fact, `vite` provides a `vite build` command to do exactly that so the app doesn't suffer from network waterfall in production.
Finally, because compilation is still done in Node, it can technically support any code transforms a bundler can, and nothing prevents you from eventually bundling the code for production. In fact, Vite provides a `vite build` command to do exactly that so the app doesn't suffer from network waterfall in production.
### How is This Different from [es-dev-server](https://open-wc.org/developing/es-dev-server.html)?
`es-dev-server` is a great project and we did take some inspiration from it when refactoring `vite` in the early stages. That said, here is why `vite` is different from `es-dev-server` and why we didn't just implement `vite` as a middleware for `es-dev-server`:
`es-dev-server` is a great project and we did take some inspiration from it when refactoring Vite in the early stages. That said, here is why Vite is different from `es-dev-server` and why we didn't just implement Vite as a middleware for `es-dev-server`:
- `vite` supports Hot Module Replacement, which surgically updates the updated module without reloading the page. This is a fundamental difference in terms of development experience. `es-dev-server` internals is a bit too opaque to get this working nicely via a middleware.
- One of Vite's primary goal was to support Hot Module Replacement, but `es-dev-server` internals is a bit too opaque to get this working nicely via a middleware.
- `vite` aims to be a single tool that integrates both the dev and the build process. You can use `vite` to both serve and bundle the same source code, with zero configuration.
- Vite aims to be a single tool that integrates both the dev and the build process. You can use Vite to both serve and bundle the same source code, with zero configuration.
- `vite` is more opinionated on how certain types of imports are handled, e.g. `.css` and static assets. The handling is similar to `vue-cli` for obvious reasons.
- Vite is more opinionated on how certain types of imports are handled, e.g. `.css` and static assets. The handling is similar to `vue-cli` for obvious reasons.
### How is This Different from [Snowpack](https://www.snowpack.dev/)?
Snowpack 2 is closer to Vite in scope - both offer bundle-free dev servers and can bundle the app for production. Some notable differences are:
- Vite has HMR, while Snowpack simply reloads the page on any file edit. This is a fundamental difference in terms of development experience:
- Since both solutions rely on native ES imports, the network waterfall of full page reloads can actually become the bottleneck in edit-to-feedback speed. HMR allows you to avoid reloading the page for the majority of your development time. The difference is already obvious in a hello world app, and will be more significant as the app size grows.
- When working on apps with complex state, HMR precisely reflects the minimum changes made while preserving unaffected application state, saving the time needed to reproduce the state you were in.
- Vite is a bit more opinionated and aims to minimize the amount of configuration required. All the features listed above like TypeScript transpilation, CSS import, and PostCSS support just work out of the box.
- While Vite can technically be used to develop apps with any framework, its main focus is to provide the best Vue development experience possible. 3rd party framework support is currently not a priority in the roadmap. On the other hand, Snowpack aims to be more flexible and support multiple frameworks at the same time.
That said, because Vite supports resolving `web_modules`, you can use Snowpack to pre-bundle dependencies (which reduces network requests during dev) in your Vite project to speed up full page reloads.
## TODOs

@@ -323,0 +356,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc