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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -18,6 +18,7 @@
"include": [
"src",
"../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
}