Skip to content

Commit

Permalink
Merge branch 'master' into fix/asset-manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
ForsakenHarmony committed Mar 29, 2022
2 parents d98b87f + a56d904 commit 86338c6
Show file tree
Hide file tree
Showing 26 changed files with 1,526 additions and 1,335 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-socks-invite.md
@@ -0,0 +1,5 @@
---
'preact-cli': patch
---

Allows users to author prerender-urls.js as ESM once again
19 changes: 18 additions & 1 deletion README.md
Expand Up @@ -266,8 +266,9 @@ preact build --prerenderUrls src/prerender-urls.json
If a static JSON file is too restrictive, you may want to provide a javascript file that exports your routes instead.
Routes can be exported as a JSON string or an object and can optionally be returned from a function.

> `prerender-urls.js`
```js
// prerender-urls.js
module.exports = [
{
url: '/',
Expand All @@ -279,6 +280,22 @@ module.exports = [
];
```

> `prerender-urls.js`
```js
export default () => {
return [
{
url: '/',
title: 'Homepage',
},
{
url: '/route/random',
},
];
};
```

#### Template

A template is used to render your page by [EJS](https://ejs.co/).
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/jest.config.js
Expand Up @@ -31,4 +31,7 @@ module.exports = {

// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",

// TODO: Restored in #1667, remove when upgrading Jest
testEnvironment: 'node',
};
32 changes: 13 additions & 19 deletions packages/cli/lib/lib/webpack/render-html-plugin.js
Expand Up @@ -5,8 +5,7 @@ const HtmlWebpackExcludeAssetsPlugin = require('html-webpack-exclude-assets-plug
const HtmlWebpackPlugin = require('html-webpack-plugin');
const prerender = require('./prerender');
const createLoadManifest = require('./create-load-manifest');
const { warn } = require('../../util');
const { info } = require('../../util');
const { esmImport, tryResolveConfig, warn } = require('../../util');

const PREACT_FALLBACK_URL = '/200.html';

Expand Down Expand Up @@ -107,21 +106,27 @@ module.exports = async function (config) {
let pages = [{ url: '/' }];

if (config.prerenderUrls) {
if (existsSync(resolve(cwd, config.prerenderUrls))) {
const prerenderUrls = tryResolveConfig(
cwd,
config.prerenderUrls,
config.prerenderUrls === 'prerender-urls.json',
config.verbose
);

if (prerenderUrls) {
try {
let result = require(resolve(cwd, config.prerenderUrls));
let result = esmImport(prerenderUrls);

if (typeof result.default !== 'undefined') {
result = result.default();
result = result.default;
}
if (typeof result === 'function') {
info(`Fetching URLs from ${config.prerenderUrls}`);
result = await result();
info(`Fetched URLs from ${config.prerenderUrls}`);
}
if (typeof result === 'string') {
result = JSON.parse(result);
}
if (result instanceof Array) {
if (Array.isArray(result)) {
pages = result;
}
} catch (error) {
Expand All @@ -131,17 +136,6 @@ module.exports = async function (config) {
}`
);
}
// don't warn if the default file doesn't exist
} else if (
config.prerenderUrls !== 'prerender-urls.json' ||
config.verbose
) {
warn(
`prerenderUrls file (${resolve(
cwd,
config.prerenderUrls
)}) doesn't exist, using default!`
);
}
}
/**
Expand Down
36 changes: 19 additions & 17 deletions packages/cli/lib/lib/webpack/transform-config.js
@@ -1,7 +1,7 @@
const { resolve } = require('path');
const webpack = require('webpack');
const { stat } = require('fs').promises;
const { error } = require('../../util');
const { error, esmImport, tryResolveConfig, warn } = require('../../util');

const FILE = 'preact.config';
const EXTENSIONS = ['js', 'json'];
Expand Down Expand Up @@ -95,24 +95,26 @@ module.exports = async function (env, webpackConfig, isServer = false) {
env.config !== 'preact.config.js'
? { configFile: env.config, isDefault: false }
: await findConfig(env);
env.config = configFile;
let myConfig = resolve(env.cwd, env.config);

try {
await stat(myConfig);
} catch (e) {
if (isDefault) return;
throw new Error(
`preact-cli config could not be loaded!\nFile ${env.config} not found.`
);
}
const cliConfig = tryResolveConfig(
env.cwd,
configFile,
isDefault,
env.verbose
);

let m = require('esm')(module)(myConfig);
if (!cliConfig) return;

// The line above results in an empty object w/ Jest,
// so we need to do the following in order to load it:
if (Object.keys(m).length === 0) {
m = require(myConfig);
let m;
try {
m = esmImport(cliConfig);
} catch (error) {
warn(
`Failed to load preact-cli config file, using default!\n${
env.verbose ? error.stack : error.message
}`
);
return;
}

const transformers = parseConfig((m && m.default) || m);
Expand All @@ -131,7 +133,7 @@ module.exports = async function (env, webpackConfig, isServer = false) {
options
);
} catch (err) {
throw new Error((`Error at ${myConfig}: \n` + err && err.stack) || err);
throw new Error((`Error at ${cliConfig}: \n` + err && err.stack) || err);
}
}
};
Expand Down
15 changes: 13 additions & 2 deletions packages/cli/lib/util.js
Expand Up @@ -30,10 +30,10 @@ exports.info = function (text, code) {
code && process.exit(code);
};

exports.warn = function (text, code) {
const warn = (exports.warn = function (text, code) {
process.stdout.write(symbols.warning + yellow(' WARN ') + text + '\n');
code && process.exit(code);
};
});

exports.error = function (text, code = 1) {
process.stderr.write(symbols.error + red(' ERROR ') + text + '\n');
Expand All @@ -56,6 +56,8 @@ exports.toBool = function (val) {
return val === void 0 || (val === 'false' ? false : val);
};

exports.esmImport = require('esm')(module);

/**
* Taken from: https://github.com/preactjs/wmr/blob/3401a9bfa6491d25108ad68688c067a7e17d0de5/packages/wmr/src/lib/net-utils.js#L4-Ll4
* Check if a port is free
Expand All @@ -78,3 +80,12 @@ exports.isPortFree = async function (port) {
return false;
}
};

exports.tryResolveConfig = function (cwd, file, isDefault, verbose) {
const path = resolve(cwd, file);
if (existsSync(path)) {
return path;
} else if (!isDefault || verbose) {
warn(`${resolve(cwd, file)} doesn't exist, using default!`);
}
};
4 changes: 2 additions & 2 deletions packages/cli/package.json
Expand Up @@ -34,9 +34,9 @@
"homepage": "https://github.com/preactjs/preact-cli",
"devDependencies": {
"@types/express": "^4.17.13",
"@types/jest": "^27.4.0",
"@types/jest": "^24.9.1",
"html-looks-like": "^1.0.2",
"jest": "^27.0.1",
"jest": "^24.9.0",
"less": "^4.1.1",
"less-loader": "^7.3.0",
"ncp": "^2.0.0",
Expand Down
63 changes: 63 additions & 0 deletions packages/cli/tests/config-formats.test.js
@@ -0,0 +1,63 @@
const { join } = require('path');
const { access } = require('fs').promises;
const { build } = require('./lib/cli');
const { subject } = require('./lib/output');

const formats = ['cjs', 'esm'];

const prerenderUrlFiles = [
'array.js',
'stringified-array.js',
'function-returning-array.js',
'function-returning-stringified-array.js',
];

const preactConfigFiles = ['function.js', 'object.js'];

describe('config files', () => {
describe('prerender-urls', () => {
it(`should load the 'prerender-urls.json' file`, async () => {
let dir = await subject('multiple-config-files');

await build(dir);

expect(await access(join(dir, 'build/index.html'))).toBeUndefined();
expect(
await access(join(dir, 'build/custom/index.html'))
).toBeUndefined();
});

formats.forEach(moduleFormat => {
prerenderUrlFiles.forEach(dataFormat => {
it(`should load the '${dataFormat}' file in ${moduleFormat}`, async () => {
let dir = await subject('multiple-config-files');

await build(dir, {
prerenderUrls: `prerenderUrls/${moduleFormat}/${dataFormat}`,
});

expect(await access(join(dir, 'build/index.html'))).toBeUndefined();
expect(
await access(join(dir, 'build/custom/index.html'))
).toBeUndefined();
});
});
});
});

describe('preact.config', () => {
formats.forEach(moduleFormat => {
preactConfigFiles.forEach(dataFormat => {
it(`should load the '${dataFormat}' file in ${moduleFormat}`, async () => {
let dir = await subject('multiple-config-files');

await build(dir, {
config: `preactConfig/${moduleFormat}/${dataFormat}`,
});

expect(await access(join(dir, 'build/bundle.js'))).toBeUndefined();
});
});
});
});
});
19 changes: 19 additions & 0 deletions packages/cli/tests/subjects/multiple-config-files/index.js
@@ -0,0 +1,19 @@
import { h, Component } from 'preact';
import { Router } from 'preact-router';
import Home from './routes/home';

export default class App extends Component {
handleRoute = e => {
this.currentUrl = e.url;
};

render(props) {
return (
<div id="app">
<Router url={props.url} onChange={this.handleRoute} {...props}>
<Home path="/" />
</Router>
</div>
);
}
}
@@ -0,0 +1,4 @@
{
"private": true,
"name": "preact-config"
}
@@ -0,0 +1,3 @@
module.exports = function (config) {
config.output.filename = '[name].js';
};
@@ -0,0 +1,5 @@
module.exports = {
webpack(config) {
config.output.filename = '[name].js';
},
};
@@ -0,0 +1,3 @@
export default function (config) {
config.output.filename = '[name].js';
}
@@ -0,0 +1,5 @@
export default {
webpack(config) {
config.output.filename = '[name].js';
},
};
@@ -0,0 +1,8 @@
[
{
"url": "/"
},
{
"url": "/custom"
}
]
@@ -0,0 +1,8 @@
module.exports = [
{
url: '/',
},
{
url: '/custom',
},
];
@@ -0,0 +1,8 @@
module.exports = () => [
{
url: '/',
},
{
url: '/custom',
},
];
@@ -0,0 +1,8 @@
module.exports = () => `[
{
"url": "/"
},
{
"url": "/custom"
}
]`;
@@ -0,0 +1,8 @@
module.exports = `[
{
"url": "/"
},
{
"url": "/custom"
}
]`;
@@ -0,0 +1,8 @@
export default [
{
url: '/',
},
{
url: '/custom',
},
];
@@ -0,0 +1,8 @@
export default () => [
{
url: '/',
},
{
url: '/custom',
},
];
@@ -0,0 +1,8 @@
export default () => `[
{
"url": "/"
},
{
"url": "/custom"
}
]`;

0 comments on commit 86338c6

Please sign in to comment.