Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2416db4
chore(cli): add debugging
KaiPrince Mar 15, 2026
caab908
chore(cli): more debug
KaiPrince Mar 15, 2026
62ad074
chore(cli): disable other workfllows for debug
KaiPrince Mar 15, 2026
8e48e31
chore(cli): faster ci
KaiPrince Mar 15, 2026
e3b4bc6
chore(cli): debug
KaiPrince Mar 15, 2026
9600658
debug
KaiPrince Mar 15, 2026
5e49583
cache ci
KaiPrince Mar 15, 2026
043a6bc
enable test
KaiPrince Mar 15, 2026
8c1d966
use checkout v6
KaiPrince Mar 15, 2026
82bdd44
revert fix should break
KaiPrince Mar 15, 2026
8454cea
duplicate with fix
KaiPrince Mar 15, 2026
f05826f
try 3 sec sleep
KaiPrince Mar 15, 2026
556069f
empty commit
KaiPrince Mar 15, 2026
7202b1e
switch to yarn v4
KaiPrince Mar 15, 2026
28f33c5
better duplicate
KaiPrince Mar 15, 2026
a777b9c
Revert "switch to yarn v4"
KaiPrince Mar 15, 2026
fd49bcb
Reapply "switch to yarn v4"
KaiPrince Mar 15, 2026
3c54838
Update install-state.gz
KaiPrince Mar 15, 2026
45c14bf
Revert "Update install-state.gz"
KaiPrince Mar 15, 2026
c3c5432
Revert "Reapply "switch to yarn v4""
KaiPrince Mar 15, 2026
2e92ae2
empty commit
KaiPrince Mar 15, 2026
a98bfa8
Reapply "Reapply "switch to yarn v4""
KaiPrince Mar 15, 2026
5f4b9dd
Reapply "Update install-state.gz"
KaiPrince Mar 15, 2026
99d7897
corepack enable
KaiPrince Mar 15, 2026
d91a24f
fix duplicate
KaiPrince Mar 15, 2026
2ed8e5a
revert yarn v4
KaiPrince Mar 15, 2026
4d7c8d3
Revert "revert yarn v4"
KaiPrince Mar 15, 2026
24e87fe
try disable yarn v4 ci cache
KaiPrince Mar 15, 2026
2717b7b
Revert "try disable yarn v4 ci cache"
KaiPrince Mar 15, 2026
21ba08b
Reapply "revert yarn v4"
KaiPrince Mar 15, 2026
85a2a3f
try fix rollup
KaiPrince Mar 15, 2026
88f7170
try fix file path
KaiPrince Mar 15, 2026
e01502b
empty commit
KaiPrince Mar 15, 2026
a9cd19d
empty commit
KaiPrince Mar 15, 2026
832231c
reverse order
KaiPrince Mar 15, 2026
68696b6
empty commit
KaiPrince Mar 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions .github/workflows/ci-loaders.yml

This file was deleted.

13 changes: 7 additions & 6 deletions .github/workflows/ci-win-loaders.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@ jobs:
node: [22]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: latest
cache: "yarn"
- name: Installing project dependencies
run: |
yarn install --frozen-lockfile --network-timeout 1000000
- name: Test
run: |
yarn test:loaders:win
- name: Test fixed
if: ${{ always() }}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, I'm not familiar with always(), what is it / does it do?

run: |
yarn test:loaders:win2
31 changes: 0 additions & 31 deletions .github/workflows/ci-win.yml

This file was deleted.

43 changes: 0 additions & 43 deletions .github/workflows/ci.yml

This file was deleted.

1 change: 0 additions & 1 deletion .husky/commit-msg

This file was deleted.

1 change: 0 additions & 1 deletion .husky/pre-commit

This file was deleted.

2 changes: 2 additions & 0 deletions .mocharc.cjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module.exports = {
timeout: 90000,
// bail: true,
// reporter: "min",
};
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"author": "Owen Buckley <owen@thegreenhouse.io>",
"license": "MIT",
"type": "module",
"packageManager": "yarn@1.22.22",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, I would be open to this as a standalone PR 👍

"workspaces": {
"packages": [
"packages/*",
Expand All @@ -21,7 +22,8 @@
"dev": "yarn workspace www dev",
"test": "cross-env BROWSERSLIST_IGNORE_OLD_DATA=true __GWD_ROLLUP_MODE__=strict NODE_NO_WARNINGS=1 c8 mocha --exclude \"./packages/**/test/cases/loaders-*/**\" \"./packages/**/**/*.spec.js\"",
"test:loaders": "cross-env BROWSERSLIST_IGNORE_OLD_DATA=true __GWD_ROLLUP_MODE__=strict NODE_NO_WARNINGS=1 node --import $(pwd)/test/test-register.js ./node_modules/mocha/bin/mocha \"./packages/**/**/*.spec.js\"",
"test:loaders:win": "cross-env BROWSERSLIST_IGNORE_OLD_DATA=true __GWD_ROLLUP_MODE__=strict NODE_NO_WARNINGS=1 node --import file:\\\\%cd%\\test\\test-register.js ./node_modules/mocha/bin/mocha --exclude \"./packages/init/test/cases/**\" \"./packages/**/**/*.spec.js\"",
"test:loaders:win": "cross-env BROWSERSLIST_IGNORE_OLD_DATA=true __GWD_ROLLUP_MODE__=strict NODE_NO_WARNINGS=1 node --import file:\\\\%cd%\\test\\test-register.js ./node_modules/mocha/bin/mocha --exclude \"./packages/init/test/cases/**\" \"./packages/cli/test/cases/build.default.import-node-modules/build.default.import-node-modules.spec.js\"",
"test:loaders:win2": "cross-env BROWSERSLIST_IGNORE_OLD_DATA=true __GWD_ROLLUP_MODE__=strict NODE_NO_WARNINGS=1 node --import file:\\\\%cd%\\test\\test-register.js ./node_modules/mocha/bin/mocha \"./packages/cli/test/cases/build.default.import-node-modules-copy/build.default.import-node-modules.spec.js\"",
"test:tdd": "yarn test --watch",
"lint": "yarn run lint:ls && yarn run lint:js && yarn run lint:types",
"lint:js": "eslint",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
/*
* Use Case
* Run Greenwood with and loading different references to node_module types to ensure proper support.
* Sets prerender: true to validate the functionality.
*
* User Result
* Should generate a bare bones Greenwood build without erroring.
*
* User Command
* greenwood build
*
* User Config
* None
*
* User Workspace
* src/
* pages/
* index.html
* scripts/
* main.js
* styles/
* theme.css
*/
import chai from "chai";
import fs from "node:fs";
import glob from "glob-promise";
import { JSDOM } from "jsdom";
import path from "node:path";
import {
getOutputTeardownFiles,
getDependencyFiles,
HASH_REGEX,
} from "../../../../../test/utils.js";
import { Runner } from "gallinago";
import { fileURLToPath } from "node:url";

const expect = chai.expect;

describe("Build Greenwood With FIXED: ", function () {
const LABEL = "Importing packages from node modules FIXED";
const cliPath = path.join(process.cwd(), "packages/cli/src/bin.js");
const outputPath = fileURLToPath(new URL(".", import.meta.url));
let runner;

before(function () {
this.context = {
publicDir: path.join(outputPath, "public"),
};
runner = new Runner();
});

describe(LABEL, function () {
let dom;

before(async function () {
// this package has a known issue with import.meta.resolve
// in that it has no main, module, or exports so it has to be hoisted
// at least for this current version, as well as for testing relative ../node_modules references
// https://unpkg.com/browse/font-awesome@4.7.0/package.json
// https://github.com/FortAwesome/Font-Awesome/pull/19041
const fontAwesomePackageJson = await getDependencyFiles(
`${process.cwd()}/node_modules/font-awesome/package.json`,
`${outputPath}/node_modules/font-awesome/`,
);
const fontAwesomeCssFiles = await getDependencyFiles(
`${process.cwd()}/node_modules/font-awesome/css/*`,
`${outputPath}/node_modules/font-awesome/css/`,
);
const fontAwesomeFontFiles = await getDependencyFiles(
`${process.cwd()}/node_modules/font-awesome/fonts/*`,
`${outputPath}/node_modules/font-awesome/fonts/`,
);

try {
await runner.setup(outputPath, [
...fontAwesomePackageJson,
...fontAwesomeCssFiles,
...fontAwesomeFontFiles,
]);
} catch (error) {
console.error("Caught busy error in setup", JSON.stringify(error, null, 2));
throw error;
}

await new Promise((resolve) => setTimeout(resolve, 3000));

try {
await runner.runCommand(cliPath, "build");
} catch (error) {
console.error("Caught busy error in build", JSON.stringify(error, null, 2));
throw error;
}

dom = await JSDOM.fromFile(path.resolve(this.context.publicDir, "index.html"));
});

describe('<script src="..."> tag in the <head> tag', function () {
it('should have one <script src="..."> tag for main.js loaded in the <head> tag', function () {
const scriptTags = dom.window.document.querySelectorAll("head > script[src]");
const mainScriptTags = Array.prototype.slice.call(scriptTags).filter((script) => {
return /main.*.js/.test(script.src);
});

expect(mainScriptTags.length).to.be.equal(1);
});

it("should have the total expected number of .js file in the output directory", async function () {
expect(await glob.promise(path.join(this.context.publicDir, "*.js"))).to.have.lengthOf(3);
});

it("should have the expected main.js file in the output directory", async function () {
expect(await glob.promise(path.join(this.context.publicDir, "main.*.js"))).to.have.lengthOf(
1,
);
});
});

describe("<script> tag with inline code in the <head> tag", function () {
it("should have one <script> tag with inline code loaded in the <head> tag", function () {
const scriptTagsInline = Array.from(
dom.window.document.querySelectorAll("head > script:not([src])"),
).filter((tag) => !tag.getAttribute("data-gwd"));

expect(scriptTagsInline.length).to.be.equal(1);
});

it("should have the expected lit related files in the output directory", async function () {
expect(await glob.promise(path.join(this.context.publicDir, "lit*.js"))).to.have.lengthOf(
1,
);
});

it("should have the expected inline node_modules content in the first inline script", async function () {
const inlineScriptTag = Array.from(
dom.window.document.querySelectorAll("head > script:not([src])"),
).filter((tag) => !tag.getAttribute("data-gwd"))[0];

expect(inlineScriptTag.textContent.replace(/\n/g, "")).to.match(
new RegExp(
`import"\\/${HASH_REGEX}\\.${HASH_REGEX}\\.js";import"\\/lit-html\\.${HASH_REGEX}\\.js";\\/\\/# sourceMappingURL=${HASH_REGEX}\\.${HASH_REGEX}\\.js\\.map`,
),
);
});
});

describe('<script src="..."> with reference to node_modules/ path in the <head> tag', function () {
it('should have one <script src="..."> tag for lit-html loaded in the <head> tag', function () {
const scriptTagsInline = dom.window.document.querySelectorAll("head > script[src]");
const litScriptTags = Array.prototype.slice.call(scriptTagsInline).filter((script) => {
return /lit-.*.js/.test(script.src);
});

expect(litScriptTags.length).to.be.equal(1);
});

it("should have the expected lit-html.js files in the output directory", async function () {
expect(
await glob.promise(path.join(this.context.publicDir, "lit-html.*.js")),
).to.have.lengthOf(1);
});
});

describe('<link rel="stylesheet" href="..."> with reference to node_modules/ path in the <head> tag', function () {
it('should have one <link href="..."> tag in the <head> tag', function () {
const linkTags = dom.window.document.querySelectorAll('head > link[rel="stylesheet"]');
const prismLinkTag = Array.prototype.slice.call(linkTags).filter((link) => {
return /prism-tomorrow.*.css/.test(link.href);
});

expect(prismLinkTag.length).to.be.equal(1);
});

it("should have the expected prism.css file in the output directory", async function () {
expect(
await glob.promise(path.join(this.context.publicDir, "prism-tomorrow.*.css")),
).to.have.lengthOf(1);
});
});

describe('<link rel="stylesheet" href="..."> with reference to node_modules with bare @import paths in the <head> tag', function () {
it('should have one <link href="..."> tag in the <head> tag', function () {
const linkTags = dom.window.document.querySelectorAll('head > link[rel="stylesheet"]');
const themeLinkTag = Array.prototype.slice.call(linkTags).filter((link) => {
return /theme.*.css/.test(link.href);
});

expect(themeLinkTag.length).to.be.equal(1);
});

it("should have the expected theme.css file in the output directory with the expected content", async function () {
const themeFile = await glob.promise(
path.join(this.context.publicDir, "styles/theme.*.css"),
);
const contents = fs.readFileSync(themeFile[0], "utf-8");

expect(themeFile).to.have.lengthOf(1);
expect(
contents.indexOf(
":root,:host{--spectrum-global-animation-linear:cubic-bezier(0, 0, 1, 1);",
),
).to.equal(0);
});
});

describe('<link rel="stylesheet" href="..."> with reference to transient relative node_modules url(...) references', function () {
it("should have the expected number of font files referenced in vendor CSS file in the output directory", async function () {
expect(
await glob.promise(
path.join(this.context.publicDir, "node-modules/font-awesome/fonts/*"),
),
).to.have.lengthOf(5);
});

it("should have the expected url link for the bundled font-awesome file", async function () {
const themeFile = await glob.promise(
path.join(this.context.publicDir, "styles/theme.*.css"),
);
const contents = fs.readFileSync(themeFile[0], "utf-8");
const contentsRegex = new RegExp(
`@font-face\\s*\\{font-family:'FontAwesome';src:url\\('/node-modules/font-awesome/fonts/fontawesome-webfont\\.${HASH_REGEX}\\.eot\\?v=4\\.7\\.0'\\);`,
);
expect(contents).to.match(contentsRegex);
});
});
});

after(async function () {
await runner.teardown(getOutputTeardownFiles(outputPath));
});
});
Loading