Replace `@vercel/ncc` with `esbuild` (#517)

* Use `esbuild`

* Replace direct `eval`

* Use `esbuild` for language server build
master
Brad Cornes 2022-04-13 13:54:33 +01:00 committed by GitHub
parent d344400688
commit 0a6e5def00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 3802 additions and 1310 deletions

76
esbuild.js 100644
View File

@ -0,0 +1,76 @@
const esbuild = require('esbuild')
const path = require('path')
const fs = require('fs')
const mri = require('mri')
const resolve = (...args) => path.resolve(__dirname, ...args)
const args = mri(process.argv.slice(2), {
boolean: ['watch', 'minify'],
string: ['outfile', 'outdir', 'external'],
})
esbuild.build({
entryPoints: args._,
bundle: true,
platform: 'node',
external: [].concat(args.external),
format: 'cjs',
outdir: args.outdir,
outfile: args.outfile,
watch: args.watch,
minify: args.minify,
plugins: [
{
name: 'css',
setup(build) {
build.onResolve({ filter: /\.css$/, namespace: 'file' }, (args) => ({
path: require.resolve(args.path, { paths: [args.resolveDir] }),
namespace: 'css',
}))
build.onLoad({ filter: /.*/, namespace: 'css' }, async (args) => ({
contents: `
export default ${JSON.stringify(await fs.promises.readFile(args.path, 'utf8'))}
`,
}))
},
},
{
// https://github.com/evanw/esbuild/issues/1051#issuecomment-806325487
name: 'native-node-modules',
setup(build) {
// If a ".node" file is imported within a module in the "file" namespace, resolve
// it to an absolute path and put it into the "node-file" virtual namespace.
build.onResolve({ filter: /\.node$/, namespace: 'file' }, (args) => ({
path: require.resolve(args.path, { paths: [args.resolveDir] }),
namespace: 'node-file',
}))
// Files in the "node-file" virtual namespace call "require()" on the
// path from esbuild of the ".node" file in the output directory.
build.onLoad({ filter: /.*/, namespace: 'node-file' }, (args) => ({
contents: `
import path from ${JSON.stringify(args.path)}
import { resolve } from 'path'
module.exports = require(resolve(__dirname, path))
`,
}))
// If a ".node" file is imported within a module in the "node-file" namespace, put
// it in the "file" namespace where esbuild's default loading behavior will handle
// it. It is already an absolute path since we resolved it to one above.
build.onResolve({ filter: /\.node$/, namespace: 'node-file' }, (args) => ({
path: args.path,
namespace: 'file',
}))
// Tell esbuild's default loading behavior to use the "file" loader for
// these ".node" files.
let opts = build.initialOptions
opts.loader = opts.loader || {}
opts.loader['.node'] = 'file'
},
},
],
})

3450
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,8 @@
"clean": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +" "clean": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +"
}, },
"devDependencies": { "devDependencies": {
"lerna": "^3.22.1" "esbuild": "0.14.11",
"lerna": "^3.22.1",
"mri": "1.2.0"
} }
} }

View File

@ -4,8 +4,9 @@
"license": "MIT", "license": "MIT",
"version": "0.0.7", "version": "0.0.7",
"scripts": { "scripts": {
"build": "npm run clean && ncc build src/server.ts -o bin --minify && mv bin/index.js bin/tailwindcss-language-server && npm run hashbang", "build": "npm run clean && npm run _esbuild && npm run hashbang",
"clean": "rimraf dist", "_esbuild": "node ../../esbuild.js src/server.ts --outfile=bin/tailwindcss-language-server --external=pnpapi --minify",
"clean": "rimraf bin",
"hashbang": "node scripts/hashbang.mjs", "hashbang": "node scripts/hashbang.mjs",
"create-notices-file": "node scripts/createNoticesFile.mjs", "create-notices-file": "node scripts/createNoticesFile.mjs",
"prepublishOnly": "npm run build" "prepublishOnly": "npm run build"
@ -29,7 +30,6 @@
"@types/debounce": "1.2.0", "@types/debounce": "1.2.0",
"@types/node": "14.14.34", "@types/node": "14.14.34",
"@types/vscode": "1.52.0", "@types/vscode": "1.52.0",
"@vercel/ncc": "0.28.4",
"builtin-modules": "3.2.0", "builtin-modules": "3.2.0",
"chokidar": "3.5.1", "chokidar": "3.5.1",
"color-name": "1.1.4", "color-name": "1.1.4",

View File

@ -6,9 +6,9 @@ import { fileURLToPath } from 'url'
const exclude = [ const exclude = [
/^@types\//, /^@types\//,
'esbuild',
'rimraf', 'rimraf',
'jest', 'jest',
'@vercel/ncc',
'prettier', 'prettier',
'terser', 'terser',
'typescript', 'typescript',

View File

@ -76,20 +76,27 @@ import { generateRules } from 'tailwindcss-language-service/src/util/jit'
import { getColor } from 'tailwindcss-language-service/src/util/color' import { getColor } from 'tailwindcss-language-service/src/util/color'
import * as culori from 'culori' import * as culori from 'culori'
import namedColors from 'color-name' import namedColors from 'color-name'
import preflight from './lib/preflight'
import tailwindPlugins from './lib/plugins' import tailwindPlugins from './lib/plugins'
import isExcluded, { DEFAULT_FILES_EXCLUDE } from './util/isExcluded' import isExcluded, { DEFAULT_FILES_EXCLUDE } from './util/isExcluded'
import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri' import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri'
import { equal } from 'tailwindcss-language-service/src/util/array' import { equal } from 'tailwindcss-language-service/src/util/array'
import preflight from 'tailwindcss/lib/css/preflight.css'
let oldReadFileSync = fs.readFileSync
// @ts-ignore // @ts-ignore
fs.readFileSync = function (filename, ...args) { global.__preflight = preflight
if (filename === path.join(__dirname, 'css/preflight.css')) { new Function(
return preflight 'require',
'__dirname',
`
let oldReadFileSync = require('fs').readFileSync
require('fs').readFileSync = function (filename, ...args) {
if (filename === require('path').join(__dirname, 'css/preflight.css')) {
return global.__preflight
} }
return oldReadFileSync(filename, ...args) return oldReadFileSync(filename, ...args)
} }
`
)(require, __dirname)
const CONFIG_FILE_GLOB = '{tailwind,tailwind.config}.{js,cjs}' const CONFIG_FILE_GLOB = '{tailwind,tailwind.config}.{js,cjs}'
const PACKAGE_GLOB = '{package.json,package-lock.json,yarn.lock,pnpm-lock.yaml}' const PACKAGE_GLOB = '{package.json,package-lock.json,yarn.lock,pnpm-lock.yaml}'
@ -112,8 +119,6 @@ const TRIGGER_CHARACTERS = [
const colorNames = Object.keys(namedColors) const colorNames = Object.keys(namedColors)
declare var __non_webpack_require__: typeof require
const connection = const connection =
process.argv.length <= 2 ? createConnection(process.stdin, process.stdout) : createConnection() process.argv.length <= 2 ? createConnection(process.stdin, process.stdout) : createConnection()
@ -434,9 +439,9 @@ async function createProjectService(
} }
function clearRequireCache(): void { function clearRequireCache(): void {
Object.keys(__non_webpack_require__.cache).forEach((key) => { Object.keys(require.cache).forEach((key) => {
if (!key.endsWith('.node')) { if (!key.endsWith('.node')) {
delete __non_webpack_require__.cache[key] delete require.cache[key]
} }
}) })
Object.keys((Module as any)._pathCache).forEach((key) => { Object.keys((Module as any)._pathCache).forEach((key) => {
@ -483,7 +488,7 @@ async function createProjectService(
) )
if (pnpPath) { if (pnpPath) {
let pnpApi = __non_webpack_require__(pnpPath) let pnpApi = require(pnpPath)
pnpApi.setup() pnpApi.setup()
setPnpApi(pnpApi) setPnpApi(pnpApi)
} }
@ -513,13 +518,13 @@ async function createProjectService(
const postcssDir = path.dirname(postcssPkgPath) const postcssDir = path.dirname(postcssPkgPath)
const postcssSelectorParserPath = resolveFrom(tailwindDir, 'postcss-selector-parser') const postcssSelectorParserPath = resolveFrom(tailwindDir, 'postcss-selector-parser')
postcssVersion = __non_webpack_require__(postcssPkgPath).version postcssVersion = require(postcssPkgPath).version
tailwindcssVersion = __non_webpack_require__(tailwindcssPkgPath).version tailwindcssVersion = require(tailwindcssPkgPath).version
pluginVersions = Object.keys(tailwindPlugins) pluginVersions = Object.keys(tailwindPlugins)
.map((plugin) => { .map((plugin) => {
try { try {
return __non_webpack_require__(resolveFrom(configDir, `${plugin}/package.json`)).version return require(resolveFrom(configDir, `${plugin}/package.json`)).version
} catch (_) { } catch (_) {
return '' return ''
} }
@ -539,32 +544,27 @@ async function createProjectService(
console.log(`Found Tailwind CSS config file: ${configPath}`) console.log(`Found Tailwind CSS config file: ${configPath}`)
postcss = __non_webpack_require__(postcssPath) postcss = require(postcssPath)
postcssSelectorParser = __non_webpack_require__(postcssSelectorParserPath) postcssSelectorParser = require(postcssSelectorParserPath)
console.log(`Loaded postcss v${postcssVersion}: ${postcssDir}`) console.log(`Loaded postcss v${postcssVersion}: ${postcssDir}`)
tailwindcss = __non_webpack_require__(tailwindcssPath) tailwindcss = require(tailwindcssPath)
console.log(`Loaded tailwindcss v${tailwindcssVersion}: ${tailwindDir}`) console.log(`Loaded tailwindcss v${tailwindcssVersion}: ${tailwindDir}`)
try { try {
resolveConfigFn = __non_webpack_require__(resolveFrom(tailwindDir, './resolveConfig.js')) resolveConfigFn = require(resolveFrom(tailwindDir, './resolveConfig.js'))
} catch (_) { } catch (_) {
try { try {
const resolveConfig = __non_webpack_require__( const resolveConfig = require(resolveFrom(tailwindDir, './lib/util/resolveConfig.js'))
resolveFrom(tailwindDir, './lib/util/resolveConfig.js') const defaultConfig = require(resolveFrom(tailwindDir, './stubs/defaultConfig.stub.js'))
)
const defaultConfig = __non_webpack_require__(
resolveFrom(tailwindDir, './stubs/defaultConfig.stub.js')
)
resolveConfigFn = (config) => resolveConfig([config, defaultConfig]) resolveConfigFn = (config) => resolveConfig([config, defaultConfig])
} catch (_) { } catch (_) {
try { try {
const resolveConfig = __non_webpack_require__( const resolveConfig = require(resolveFrom(
resolveFrom(tailwindDir, './lib/util/mergeConfigWithDefaults.js') tailwindDir,
) './lib/util/mergeConfigWithDefaults.js'
const defaultConfig = __non_webpack_require__( ))
resolveFrom(tailwindDir, './defaultConfig.js') const defaultConfig = require(resolveFrom(tailwindDir, './defaultConfig.js'))
)
resolveConfigFn = (config) => resolveConfig(config, defaultConfig()) resolveConfigFn = (config) => resolveConfig(config, defaultConfig())
} catch (_) { } catch (_) {
throw Error('Failed to load resolveConfig function.') throw Error('Failed to load resolveConfig function.')
@ -575,23 +575,19 @@ async function createProjectService(
if (semver.gte(tailwindcssVersion, '1.4.0') && semver.lte(tailwindcssVersion, '1.99.0')) { if (semver.gte(tailwindcssVersion, '1.4.0') && semver.lte(tailwindcssVersion, '1.99.0')) {
const browserslistPath = resolveFrom(tailwindDir, 'browserslist') const browserslistPath = resolveFrom(tailwindDir, 'browserslist')
// TODO: set path to nearest dir with package.json? // TODO: set path to nearest dir with package.json?
browserslist = __non_webpack_require__(browserslistPath)(undefined, { path: folder }) browserslist = require(browserslistPath)(undefined, { path: folder })
} }
if (semver.gte(tailwindcssVersion, '1.99.0')) { if (semver.gte(tailwindcssVersion, '1.99.0')) {
applyComplexClasses = firstOptional(() => applyComplexClasses = firstOptional(() =>
__non_webpack_require__(resolveFrom(tailwindDir, './lib/lib/substituteClassApplyAtRules')) require(resolveFrom(tailwindDir, './lib/lib/substituteClassApplyAtRules'))
) )
} else if (semver.gte(tailwindcssVersion, '1.7.0')) { } else if (semver.gte(tailwindcssVersion, '1.7.0')) {
applyComplexClasses = __non_webpack_require__( applyComplexClasses = require(resolveFrom(tailwindDir, './lib/flagged/applyComplexClasses'))
resolveFrom(tailwindDir, './lib/flagged/applyComplexClasses')
)
} }
try { try {
featureFlags = __non_webpack_require__( featureFlags = require(resolveFrom(tailwindDir, './lib/featureFlags.js')).default
resolveFrom(tailwindDir, './lib/featureFlags.js')
).default
} catch (_) {} } catch (_) {}
// stubs // stubs
@ -603,24 +599,27 @@ async function createProjectService(
try { try {
let createContext = first( let createContext = first(
() => { () => {
let createContextFn = __non_webpack_require__( let createContextFn = require(resolveFrom(
resolveFrom(configDir, 'tailwindcss/lib/lib/setupContextUtils') configDir,
).createContext 'tailwindcss/lib/lib/setupContextUtils'
)).createContext
assert.strictEqual(typeof createContextFn, 'function') assert.strictEqual(typeof createContextFn, 'function')
return (state) => createContextFn(state.config) return (state) => createContextFn(state.config)
}, },
() => { () => {
let createContextFn = __non_webpack_require__( let createContextFn = require(resolveFrom(
resolveFrom(configDir, 'tailwindcss/lib/jit/lib/setupContextUtils') configDir,
).createContext 'tailwindcss/lib/jit/lib/setupContextUtils'
)).createContext
assert.strictEqual(typeof createContextFn, 'function') assert.strictEqual(typeof createContextFn, 'function')
return (state) => createContextFn(state.config) return (state) => createContextFn(state.config)
}, },
// TODO: the next two are canary releases only so can probably be removed // TODO: the next two are canary releases only so can probably be removed
() => { () => {
let setupTrackingContext = __non_webpack_require__( let setupTrackingContext = require(resolveFrom(
resolveFrom(configDir, 'tailwindcss/lib/jit/lib/setupTrackingContext') configDir,
).default 'tailwindcss/lib/jit/lib/setupTrackingContext'
)).default
assert.strictEqual(typeof setupTrackingContext, 'function') assert.strictEqual(typeof setupTrackingContext, 'function')
return (state) => return (state) =>
setupTrackingContext( setupTrackingContext(
@ -630,9 +629,10 @@ async function createProjectService(
)(result, root) )(result, root)
}, },
() => { () => {
let setupContext = __non_webpack_require__( let setupContext = require(resolveFrom(
resolveFrom(configDir, 'tailwindcss/lib/jit/lib/setupContext') configDir,
).default 'tailwindcss/lib/jit/lib/setupContext'
)).default
assert.strictEqual(typeof setupContext, 'function') assert.strictEqual(typeof setupContext, 'function')
return (state) => setupContext(state.configPath, tailwindDirectives)(result, root) return (state) => setupContext(state.configPath, tailwindDirectives)(result, root)
} }
@ -642,12 +642,10 @@ async function createProjectService(
generateRules: { generateRules: {
module: first( module: first(
() => () =>
__non_webpack_require__(resolveFrom(configDir, 'tailwindcss/lib/lib/generateRules')) require(resolveFrom(configDir, 'tailwindcss/lib/lib/generateRules')).generateRules,
.generateRules,
() => () =>
__non_webpack_require__( require(resolveFrom(configDir, 'tailwindcss/lib/jit/lib/generateRules'))
resolveFrom(configDir, 'tailwindcss/lib/jit/lib/generateRules') .generateRules
).generateRules
), ),
}, },
createContext: { createContext: {
@ -656,35 +654,27 @@ async function createProjectService(
expandApplyAtRules: { expandApplyAtRules: {
module: first( module: first(
() => () =>
__non_webpack_require__( require(resolveFrom(configDir, 'tailwindcss/lib/lib/expandApplyAtRules')).default,
resolveFrom(configDir, 'tailwindcss/lib/lib/expandApplyAtRules')
).default,
() => () =>
__non_webpack_require__( require(resolveFrom(configDir, 'tailwindcss/lib/jit/lib/expandApplyAtRules'))
resolveFrom(configDir, 'tailwindcss/lib/jit/lib/expandApplyAtRules') .default
).default
), ),
}, },
} }
} catch (_) { } catch (_) {
try { try {
let setupContext = __non_webpack_require__( let setupContext = require(resolveFrom(configDir, 'tailwindcss/jit/lib/setupContext'))
resolveFrom(configDir, 'tailwindcss/jit/lib/setupContext')
)
jitModules = { jitModules = {
generateRules: { generateRules: {
module: __non_webpack_require__( module: require(resolveFrom(configDir, 'tailwindcss/jit/lib/generateRules'))
resolveFrom(configDir, 'tailwindcss/jit/lib/generateRules') .generateRules,
).generateRules,
}, },
createContext: { createContext: {
module: (state) => setupContext(state.configPath, tailwindDirectives)(result, root), module: (state) => setupContext(state.configPath, tailwindDirectives)(result, root),
}, },
expandApplyAtRules: { expandApplyAtRules: {
module: __non_webpack_require__( module: require(resolveFrom(configDir, 'tailwindcss/jit/lib/expandApplyAtRules')),
resolveFrom(configDir, 'tailwindcss/jit/lib/expandApplyAtRules')
),
}, },
} }
} catch (_) {} } catch (_) {}
@ -726,9 +716,7 @@ async function createProjectService(
try { try {
state.corePlugins = Object.keys( state.corePlugins = Object.keys(
__non_webpack_require__( require(resolveFrom(path.dirname(state.configPath), 'tailwindcss/lib/plugins/index.js'))
resolveFrom(path.dirname(state.configPath), 'tailwindcss/lib/plugins/index.js')
)
) )
} catch (_) {} } catch (_) {}
@ -883,7 +871,7 @@ async function createProjectService(
}) })
try { try {
__non_webpack_require__(state.configPath) require(state.configPath)
} catch (error) { } catch (error) {
hook.unhook() hook.unhook()
throw error throw error
@ -1314,7 +1302,7 @@ async function getPlugins(config: any) {
} }
let pkg: any let pkg: any
try { try {
pkg = __non_webpack_require__(pkg) pkg = require(pkg)
} catch (_) { } catch (_) {
return { return {
name: fnName, name: fnName,

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,7 @@
"activationEvents": [ "activationEvents": [
"onStartupFinished" "onStartupFinished"
], ],
"main": "dist/extension/index.js", "main": "dist/extension.js",
"capabilities": { "capabilities": {
"virtualWorkspaces": false "virtualWorkspaces": false
}, },
@ -258,21 +258,22 @@
} }
}, },
"scripts": { "scripts": {
"dev": "npm run clean && glob-exec --foreach --parallel \"src/*.ts\" -- \"ncc build {{file}} --watch -o dist/{{file.toString().replace(/^src\\//, '').replace(/\\.ts$/, '')}}\"", "_esbuild": "node ../../esbuild.js src/extension.ts src/server.ts --outdir=dist --external=pnpapi --external=vscode",
"build": "npm run clean && glob-exec --foreach --parallel \"src/*.ts\" -- \"ncc build {{file}} -o dist/{{file.toString().replace(/^src\\//, '').replace(/\\.ts$/, '')}}\" && mv dist/server/index.js dist/server/tailwindServer.js && npm run minify", "dev": "concurrently --raw --kill-others \"npm run watch\" \"npm run check -- --watch\"",
"minify": "glob-exec --foreach --parallel \"dist/**/*.js\" -- \"terser {{file}} --compress --mangle --output {{file.toString()}}\"", "watch": "npm run clean && npm run _esbuild -- --watch",
"build": "npm run check && npm run clean && npm run _esbuild -- --minify && mv dist/server.js dist/tailwindServer.js",
"package": "vsce package", "package": "vsce package",
"publish": "vsce publish", "publish": "vsce publish",
"copy:notices": "cp ../tailwindcss-language-server/ThirdPartyNotices.txt ./dist/ThirdPartyNotices.txt", "copy:notices": "cp ../tailwindcss-language-server/ThirdPartyNotices.txt ./dist/ThirdPartyNotices.txt",
"vscode:prepublish": "npm run build && npm run copy:notices", "vscode:prepublish": "npm run build && npm run copy:notices",
"clean": "rimraf dist", "clean": "rimraf dist",
"test": "jest" "test": "jest",
"check": "tsc --noEmit"
}, },
"devDependencies": { "devDependencies": {
"@types/vscode": "1.52.0", "@types/vscode": "1.52.0",
"@vercel/ncc": "0.28.4",
"color-name": "1.1.4", "color-name": "1.1.4",
"glob-exec": "0.1.1", "concurrently": "7.0.0",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"terser": "4.6.12", "terser": "4.6.12",
"vsce": "1.87.0", "vsce": "1.87.0",

View File

@ -123,8 +123,8 @@ function mergeExcludes(settings: WorkspaceConfiguration, scope: ConfigurationSco
} }
export async function activate(context: ExtensionContext) { export async function activate(context: ExtensionContext) {
let module = context.asAbsolutePath(path.join('dist', 'server', 'index.js')) let module = context.asAbsolutePath(path.join('dist', 'server.js'))
let prod = path.join('dist', 'server', 'tailwindServer.js') let prod = path.join('dist', 'tailwindServer.js')
try { try {
await Workspace.fs.stat(Uri.joinPath(context.extensionUri, prod)) await Workspace.fs.stat(Uri.joinPath(context.extensionUri, prod))

View File

@ -18,6 +18,7 @@
"include": [ "include": [
"src", "src",
"../packages/tailwindcss-language-service", "../packages/tailwindcss-language-service",
"../packages/tailwindcss-language-server" "../packages/tailwindcss-language-server",
"../../types"
] ]
} }

4
types/global.d.ts vendored 100644
View File

@ -0,0 +1,4 @@
declare module '*.css' {
let content: string
export default content
}