123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- // @ts-check
- import fs from 'fs'
- import path from 'path'
- import nodeResolve from '@rollup/plugin-node-resolve'
- import typescript from '@rollup/plugin-typescript'
- import commonjs from '@rollup/plugin-commonjs'
- import json from '@rollup/plugin-json'
- import alias from '@rollup/plugin-alias'
- import license from 'rollup-plugin-license'
- import MagicString from 'magic-string'
- import chalk from 'chalk'
- import fg from 'fast-glob'
- import { sync as resolve } from 'resolve'
- /**
- * @type { import('rollup').RollupOptions }
- */
- const envConfig = {
- input: path.resolve(__dirname, 'src/client/env.ts'),
- plugins: [
- typescript({
- target: 'es2018',
- include: ['src/client/env.ts'],
- baseUrl: path.resolve(__dirname, 'src/env'),
- paths: {
- 'types/*': ['../../types/*']
- }
- })
- ],
- output: {
- file: path.resolve(__dirname, 'dist/client', 'env.mjs'),
- sourcemap: true
- }
- }
- /**
- * @type { import('rollup').RollupOptions }
- */
- const clientConfig = {
- input: path.resolve(__dirname, 'src/client/client.ts'),
- external: ['./env'],
- plugins: [
- typescript({
- target: 'es2018',
- include: ['src/client/**/*.ts'],
- baseUrl: path.resolve(__dirname, 'src/client'),
- paths: {
- 'types/*': ['../../types/*']
- }
- })
- ],
- output: {
- file: path.resolve(__dirname, 'dist/client', 'client.mjs'),
- sourcemap: true
- }
- }
- /**
- * @type { import('rollup').RollupOptions }
- */
- const sharedNodeOptions = {
- treeshake: {
- moduleSideEffects: 'no-external',
- propertyReadSideEffects: false,
- tryCatchDeoptimization: false
- },
- output: {
- dir: path.resolve(__dirname, 'dist'),
- entryFileNames: `node/[name].js`,
- chunkFileNames: 'node/chunks/dep-[hash].js',
- exports: 'named',
- format: 'cjs',
- externalLiveBindings: false,
- freeze: false,
- sourcemap: true
- },
- onwarn(warning, warn) {
- // node-resolve complains a lot about this but seems to still work?
- if (warning.message.includes('Package subpath')) {
- return
- }
- // we use the eval('require') trick to deal with optional deps
- if (warning.message.includes('Use of eval')) {
- return
- }
- if (warning.message.includes('Circular dependency')) {
- return
- }
- warn(warning)
- }
- }
- /**
- *
- * @param {boolean} isProduction
- * @returns {import('rollup').RollupOptions}
- */
- const createNodeConfig = (isProduction) => {
- /**
- * @type { import('rollup').RollupOptions }
- */
- const nodeConfig = {
- ...sharedNodeOptions,
- input: {
- index: path.resolve(__dirname, 'src/node/index.ts'),
- cli: path.resolve(__dirname, 'src/node/cli.ts')
- },
- external: [
- 'fsevents',
- ...Object.keys(require('./package.json').dependencies),
- ...(isProduction
- ? []
- : Object.keys(require('./package.json').devDependencies))
- ],
- plugins: [
- alias({
- // packages with "module" field that doesn't play well with cjs bundles
- entries: {
- '@vue/compiler-dom': require.resolve(
- '@vue/compiler-dom/dist/compiler-dom.cjs.js'
- ),
- 'big.js': require.resolve('big.js/big.js')
- }
- }),
- nodeResolve({ preferBuiltins: true }),
- typescript({
- target: 'es2019',
- include: ['src/**/*.ts', 'types/**'],
- exclude: ['src/**/__tests__/**'],
- esModuleInterop: true,
- // in production we use api-extractor for dts generation
- // in development we need to rely on the rollup ts plugin
- ...(isProduction
- ? {}
- : {
- tsconfig: 'tsconfig.base.json',
- declaration: true,
- declarationDir: path.resolve(__dirname, 'dist/')
- })
- }),
- // Some deps have try...catch require of optional deps, but rollup will
- // generate code that force require them upfront for side effects.
- // Shim them with eval() so rollup can skip these calls.
- isProduction &&
- shimDepsPlugin({
- 'plugins/terser.ts': {
- src: `require.resolve('terser'`,
- replacement: `require.resolve('vite/dist/node/terser'`
- },
- // chokidar -> fsevents
- 'fsevents-handler.js': {
- src: `require('fsevents')`,
- replacement: `eval('require')('fsevents')`
- },
- // cac re-assigns module.exports even in its mjs dist
- 'cac/dist/index.mjs': {
- src: `if (typeof module !== "undefined") {`,
- replacement: `if (false) {`
- },
- // postcss-import -> sugarss
- 'process-content.js': {
- src: 'require("sugarss")',
- replacement: `eval('require')('sugarss')`
- },
- 'import-from/index.js': {
- pattern: /require\(resolveFrom/g,
- replacement: `eval('require')(resolveFrom`
- },
- 'lilconfig/dist/index.js': {
- pattern: /: require,/g,
- replacement: `: eval('require'),`
- }
- }),
- commonjs({
- extensions: ['.js'],
- // Optional peer deps of ws. Native deps that are mostly for performance.
- // Since ws is not that perf critical for us, just ignore these deps.
- ignore: ['bufferutil', 'utf-8-validate']
- }),
- json(),
- isProduction && licensePlugin()
- ]
- }
- return nodeConfig
- }
- /**
- * Terser needs to be run inside a worker, so it cannot be part of the main
- * bundle. We produce a separate bundle for it and shims plugin/terser.ts to
- * use the production path during build.
- *
- * @type { import('rollup').RollupOptions }
- */
- const terserConfig = {
- ...sharedNodeOptions,
- output: {
- ...sharedNodeOptions.output,
- exports: 'default'
- },
- input: {
- terser: require.resolve('terser')
- },
- plugins: [nodeResolve(), commonjs()]
- }
- /**
- * @type { (deps: Record<string, { src?: string, replacement: string, pattern?: RegExp }>) => import('rollup').Plugin }
- */
- function shimDepsPlugin(deps) {
- const transformed = {}
- return {
- name: 'shim-deps',
- transform(code, id) {
- for (const file in deps) {
- if (id.replace(/\\/g, '/').endsWith(file)) {
- const { src, replacement, pattern } = deps[file]
- const magicString = new MagicString(code)
- if (src) {
- const pos = code.indexOf(src)
- if (pos < 0) {
- this.error(
- `Could not find expected src "${src}" in file "${file}"`
- )
- }
- transformed[file] = true
- magicString.overwrite(pos, pos + src.length, replacement)
- console.log(`shimmed: ${file}`)
- }
- if (pattern) {
- let match
- while ((match = pattern.exec(code))) {
- transformed[file] = true
- const start = match.index
- const end = start + match[0].length
- magicString.overwrite(start, end, replacement)
- }
- if (!transformed[file]) {
- this.error(
- `Could not find expected pattern "${pattern}" in file "${file}"`
- )
- }
- console.log(`shimmed: ${file}`)
- }
- return {
- code: magicString.toString(),
- map: magicString.generateMap({ hires: true })
- }
- }
- }
- },
- buildEnd(err) {
- if (!err) {
- for (const file in deps) {
- if (!transformed[file]) {
- this.error(
- `Did not find "${file}" which is supposed to be shimmed, was the file renamed?`
- )
- }
- }
- }
- }
- }
- }
- function licensePlugin() {
- return license({
- thirdParty(dependencies) {
- // https://github.com/rollup/rollup/blob/master/build-plugins/generate-license-file.js
- // MIT Licensed https://github.com/rollup/rollup/blob/master/LICENSE-CORE.md
- const coreLicense = fs.readFileSync(
- path.resolve(__dirname, '../../LICENSE')
- )
- function sortLicenses(licenses) {
- let withParenthesis = []
- let noParenthesis = []
- licenses.forEach((license) => {
- if (/^\(/.test(license)) {
- withParenthesis.push(license)
- } else {
- noParenthesis.push(license)
- }
- })
- withParenthesis = withParenthesis.sort()
- noParenthesis = noParenthesis.sort()
- return [...noParenthesis, ...withParenthesis]
- }
- const licenses = new Set()
- const dependencyLicenseTexts = dependencies
- .sort(({ name: nameA }, { name: nameB }) =>
- nameA > nameB ? 1 : nameB > nameA ? -1 : 0
- )
- .map(
- ({
- name,
- license,
- licenseText,
- author,
- maintainers,
- contributors,
- repository
- }) => {
- let text = `## ${name}\n`
- if (license) {
- text += `License: ${license}\n`
- }
- const names = new Set()
- if (author && author.name) {
- names.add(author.name)
- }
- for (const person of maintainers.concat(contributors)) {
- if (person && person.name) {
- names.add(person.name)
- }
- }
- if (names.size > 0) {
- text += `By: ${Array.from(names).join(', ')}\n`
- }
- if (repository) {
- text += `Repository: ${repository.url || repository}\n`
- }
- if (!licenseText) {
- try {
- const pkgDir = path.dirname(
- resolve(path.join(name, 'package.json'), {
- preserveSymlinks: false
- })
- )
- const licenseFile = fg.sync(`${pkgDir}/LICENSE*`, {
- caseSensitiveMatch: false
- })[0]
- if (licenseFile) {
- licenseText = fs.readFileSync(licenseFile, 'utf-8')
- }
- } catch {}
- }
- if (licenseText) {
- text +=
- '\n' +
- licenseText
- .trim()
- .replace(/(\r\n|\r)/gm, '\n')
- .split('\n')
- .map((line) => `> ${line}`)
- .join('\n') +
- '\n'
- }
- licenses.add(license)
- return text
- }
- )
- .join('\n---------------------------------------\n\n')
- const licenseText =
- `# Vite core license\n` +
- `Vite is released under the MIT license:\n\n` +
- coreLicense +
- `\n# Licenses of bundled dependencies\n` +
- `The published Vite artifact additionally contains code with the following licenses:\n` +
- `${sortLicenses(licenses).join(', ')}\n\n` +
- `# Bundled dependencies:\n` +
- dependencyLicenseTexts
- const existingLicenseText = fs.readFileSync('LICENSE.md', 'utf8')
- if (existingLicenseText !== licenseText) {
- fs.writeFileSync('LICENSE.md', licenseText)
- console.warn(
- chalk.yellow(
- '\nLICENSE.md updated. You should commit the updated file.\n'
- )
- )
- }
- }
- })
- }
- export default (commandLineArgs) => {
- const isDev = commandLineArgs.watch
- const isProduction = !isDev
- return [
- envConfig,
- clientConfig,
- createNodeConfig(isProduction),
- ...(isProduction ? [terserConfig] : [])
- ]
- }
|