-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Export
run
function as a streamlined but flexible main entrypoint (#10
) Introduce a new `assets.run` entrypoint function that is: - Streamlined enough for us to generate into every new Hanami app - But flexible enough for users to provide arbitrary esbuild customisations Here's what a default `config/assets.mjs` file would look like using this API: ```js import * as assets from "hanami-assets"; await assets.run(); ``` And here's how it would look to add a custom esbuild plugin: ```js import * as assets from "hanami-assets"; import postcss from "esbuild-postcss"; await assets.run({ esbuildOptionsFn: (args, esbuildOptions) => { const plugins = [...esbuildOptions.plugins, postcss()]; return { ...esbuildOptions, plugins, }; }, }); ``` Also: - Remove the config indicating that this package exposes an executable. Running via a ` config/assets.mjs` script is now the one and only way to use this package. - Use Prettier for JS file linting/auto-formatting. - Update TypeScript `compilerOptions` to use `"module": "NodeNext"` (per their recommendations for modern Node projects)
- Loading branch information
Showing
32 changed files
with
836 additions
and
559 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Ignore artifacts | ||
dist | ||
|
||
# Ignore non-JS files | ||
*.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{ "printWidth": 100 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,3 @@ test: build | |
build: | ||
rm -rf $(BUILD_DIR) | ||
npm run build | ||
chmod +x $(BUILD_DIR)/hanami-assets.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export interface Args { | ||
watch: Boolean; | ||
sri: string[] | null; | ||
} | ||
export declare const parseArgs: (args: string[]) => Args; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export const parseArgs = (args) => { | ||
const result = {}; | ||
args.forEach((arg) => { | ||
const [key, value] = arg.replace(/^--/, "").split("="); | ||
result[key] = value; | ||
}); | ||
return { | ||
watch: result.hasOwnProperty("watch"), | ||
sri: result["sri"]?.split(","), | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Plugin } from "esbuild"; | ||
export interface PluginOptions { | ||
root: string; | ||
publicDir: string; | ||
destDir: string; | ||
manifestPath: string; | ||
sriAlgorithms: Array<string>; | ||
hash: boolean; | ||
} | ||
export declare const defaults: Pick<PluginOptions, "root" | "publicDir" | "destDir" | "manifestPath" | "sriAlgorithms" | "hash">; | ||
declare const hanamiEsbuild: (options?: PluginOptions) => Plugin; | ||
export default hanamiEsbuild; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { BuildOptions, Plugin } from "esbuild"; | ||
import { Args } from "./args.js"; | ||
export interface EsbuildOptions extends Partial<BuildOptions> { | ||
plugins: Plugin[]; | ||
} | ||
export declare const buildOptions: (root: string, args: Args) => EsbuildOptions; | ||
export declare const watchOptions: (root: string, args: Args) => EsbuildOptions; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import path from "path"; | ||
import { globSync } from "glob"; | ||
import esbuildPlugin, { defaults as pluginDefaults } from "./esbuild-plugin.js"; | ||
const loader = { | ||
".tsx": "tsx", | ||
".ts": "ts", | ||
".js": "js", | ||
".jsx": "jsx", | ||
".json": "json", | ||
".png": "file", | ||
".jpg": "file", | ||
".jpeg": "file", | ||
".gif": "file", | ||
".svg": "file", | ||
".woff": "file", | ||
".woff2": "file", | ||
".otf": "file", | ||
".eot": "file", | ||
".ttf": "file", | ||
}; | ||
const entryPointExtensions = "app.{js,ts,mjs,mts,tsx,jsx}"; | ||
// FIXME: make cross platform | ||
const entryPointsMatcher = /(app\/assets\/js\/|slices\/(.*\/)assets\/js\/)/; | ||
const findEntryPoints = (root) => { | ||
const result = {}; | ||
// TODO: should this be done explicitly within the root? | ||
const entryPoints = globSync([ | ||
path.join("app", "assets", "js", "**", entryPointExtensions), | ||
path.join("slices", "*", "assets", "js", "**", entryPointExtensions), | ||
]); | ||
entryPoints.forEach((entryPoint) => { | ||
let modifiedPath = entryPoint.replace(entryPointsMatcher, "$2"); | ||
const relativePath = path.relative(root, modifiedPath); | ||
const { dir, name } = path.parse(relativePath); | ||
if (dir) { | ||
modifiedPath = path.join(dir, name); | ||
} | ||
else { | ||
modifiedPath = name; | ||
} | ||
result[modifiedPath] = entryPoint; | ||
}); | ||
return result; | ||
}; | ||
// TODO: feels like this really should be passed a root too, to become the cwd for globSync | ||
const externalDirectories = () => { | ||
const assetDirsPattern = [ | ||
path.join("app", "assets", "*"), | ||
path.join("slices", "*", "assets", "*"), | ||
]; | ||
const excludeDirs = ["js", "css"]; | ||
try { | ||
const dirs = globSync(assetDirsPattern, { nodir: false }); | ||
const filteredDirs = dirs.filter((dir) => { | ||
const dirName = dir.split(path.sep).pop(); | ||
return !excludeDirs.includes(dirName); | ||
}); | ||
return filteredDirs.map((dir) => path.join(dir, "*")); | ||
} | ||
catch (err) { | ||
console.error("Error listing external directories:", err); | ||
return []; | ||
} | ||
}; | ||
// TODO: reuse the logic between these two methods below | ||
export const buildOptions = (root, args) => { | ||
const pluginOptions = { | ||
...pluginDefaults, | ||
sriAlgorithms: args.sri || [], | ||
}; | ||
const plugin = esbuildPlugin(pluginOptions); | ||
const options = { | ||
bundle: true, | ||
outdir: path.join(root, "public", "assets"), | ||
absWorkingDir: root, | ||
loader: loader, | ||
external: externalDirectories(), | ||
logLevel: "silent", | ||
minify: true, | ||
sourcemap: true, | ||
entryNames: "[dir]/[name]-[hash]", | ||
entryPoints: findEntryPoints(root), | ||
plugins: [plugin], | ||
}; | ||
return options; | ||
}; | ||
export const watchOptions = (root, args) => { | ||
const pluginOptions = { | ||
...pluginDefaults, | ||
hash: false, | ||
}; | ||
const plugin = esbuildPlugin(pluginOptions); | ||
const options = { | ||
bundle: true, | ||
outdir: path.join(root, "public", "assets"), | ||
absWorkingDir: root, | ||
loader: loader, | ||
external: externalDirectories(), | ||
logLevel: "info", | ||
minify: false, | ||
sourcemap: false, | ||
entryNames: "[dir]/[name]", | ||
entryPoints: findEntryPoints(root), | ||
plugins: [plugin], | ||
}; | ||
return options; | ||
}; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.