Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2407 Add yarn serve #2618

Merged
merged 7 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"prepare": "node scripts/monorepo-introduction.js",
"prettier": "prettier --loglevel warn --write '@(packages|scripts)/**/*.@(css|graphql|js)' '*.js'",
"prettier:check": "prettier --list-different '@(packages|scripts)/**/*.@(css|graphql|js)' '*.js'",
"stage:venia": "yarn venia run start",
"stage:venia": "yarn venia start",
"stats:venia": "yarn venia run build:analyze && yarn venia run stats",
"storybook:venia": "yarn workspace @magento/venia-ui run storybook",
"test": "jest",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const mock = {
before: jest.fn(),
after: jest.fn(),
visitor: {
'index.js': jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
jest.mock('../../util/klaw-bound-fs');
const walk = require('../../util/klaw-bound-fs');
const createProject = require('../createProject');
const { resolve } = require('path');
const klaw = jest.requireActual('../../util/klaw-bound-fs');

// can't spy because it exports a function
walk.mockImplementation(klaw);

const mockBase = require.resolve('buildpack-template-package');

Expand Down Expand Up @@ -55,18 +61,24 @@ test('createProject fails if a handler fails', async () => {
).rejects.toThrow('bleh');
});

test('createProject will not run a missing after()', async () => {
mock.after = false;
test('createProject will not try to resolve a rejected promise if a trailing end event happens', async () => {
walk.mockImplementationOnce((...args) => {
const walker = klaw(...args);
setImmediate(() => {
walker.emit('error', new Error('oopes'));
walker.emit('end'); // will it reject?
});
return walker;
});
await expect(
createProject({
template: 'buildpack-template-package',
directory: 'fake/path'
})
).resolves.toBe(undefined);
).rejects.toThrow('oopes');
});

test('createProject will not run files in gitignore', async () => {
mock.after = false;
await expect(
createProject({
template: 'buildpack-template-package',
Expand All @@ -77,9 +89,21 @@ test('createProject will not run files in gitignore', async () => {
expect(mock.visitor['ignoreexp/*'].mock.calls[0]).not.toBeTruthy();
});

test('createProject will not die with a missing gitignore', async () => {
createProject.GITIGNORE_FILE = 'nonexistent-gitignore';
mock.after = false;
test('createProject will accept a custom gitignore', async () => {
mock.ignores = ['*ignore*'];
await expect(
createProject({
template: 'buildpack-template-package',
directory: 'fake/path'
})
).resolves.toBe(undefined);
expect(mock.visitor['index.js']).toHaveBeenCalled();
expect(mock.visitor['ignoreexp/*'].mock.calls[0]).not.toBeTruthy();
delete mock.ignores;
});

test('createProject will not die with a busted gitignore', async () => {
createProject.GITIGNORE_FILE = false;
await expect(
createProject({
template: 'buildpack-template-package',
Expand All @@ -89,3 +113,14 @@ test('createProject will not die with a missing gitignore', async () => {
expect(mock.visitor['index.js']).toHaveBeenCalled();
expect(mock.visitor['ignoreexp/*']).toHaveBeenCalled();
});

test('createProject will support optional before/after functions', async () => {
delete mock.before;
delete mock.after;
await expect(
createProject({
template: 'buildpack-template-package',
directory: 'fake/path'
})
).resolves.toBe(undefined);
});
30 changes: 13 additions & 17 deletions packages/pwa-buildpack/lib/Utilities/createProject.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,22 @@ const makeCopyStream = ({
!isMatch(p, ignores)
});

copyStream.on('error', e => {
failed = true;
fail(e);
});
copyStream.on('readable', function() {
let item;
while (!failed && (item = this.read())) {
debug(`visiting ${item.path}`);
try {
visit(item);
} catch (e) {
failed = true;
fail(e);
this.emit('error', e);
break;
}
}
});
copyStream.on('error', () => {
failed = true;
fail();
});
copyStream.on('end', () => {
if (!failed) {
succeed();
Expand All @@ -102,20 +102,18 @@ async function createProject(options) {
const { instructions, packageRoot } = getBuildpackInstructions(template, [
'create'
]);

const {
after,
before,
visitor,
ignores = getIgnores(packageRoot)
after = () => {},
before = () => {},
ignores = getIgnores(packageRoot),
visitor
} = instructions.create({
fs: fse,
tasks: makeCommonTasks(fse),
options
});

if (before) {
await before({ options });
}
await before({ options });
await makeCopyStream({
fs: fse,
packageRoot,
Expand All @@ -124,9 +122,7 @@ async function createProject(options) {
ignores,
visitor
});
if (after) {
await after({ options });
}
await after({ options });
}

module.exports = createProject;
Expand Down
89 changes: 89 additions & 0 deletions packages/pwa-buildpack/lib/Utilities/serve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
const loadEnvironment = require('../Utilities/loadEnvironment');
const path = require('path');

module.exports = async function serve(dirname) {
const config = loadEnvironment(dirname);
if (config.error) {
// loadEnvironment takes care of logging it
throw new Error('Can not load environment config!');
}

const prettyLogger = require('../util/pretty-logger');
const addImgOptMiddleware = require('./addImgOptMiddleware');
const stagingServerSettings = config.section('stagingServer');

process.chdir(path.join(dirname, 'dist'));

const upwardServerOptions = Object.assign(
// defaults
{
bindLocal: true,
logUrl: true
},
config.section('upwardJs'),
stagingServerSettings, // overrides upward options
{
env: process.env,
before(app) {
addImgOptMiddleware(app, {
...config.section('imageOptimizing'),
...config.section('imageService')
});
}
}
);

let envPort;
if (process.env.PORT) {
prettyLogger.info(`PORT is set in environment: ${process.env.PORT}`);
envPort = process.env.PORT;
} else if (stagingServerSettings.port) {
prettyLogger.info(
`STAGING_SERVER_PORT is configured: ${stagingServerSettings.port}`
);
envPort = stagingServerSettings.port;
}

if (config.isProd) {
prettyLogger.info(
`NODE_ENV=production, will not attempt to use custom host or port`
);

if (envPort) {
upwardServerOptions.port = envPort;
} else {
prettyLogger.warn(`No port set. Binding to OS-assigned port`);
upwardServerOptions.port = 0;
}
} else {
const customOrigin = config.section('customOrigin');
if (customOrigin.enabled) {
try {
// don't require configureHost until you need to, since loading
// the devcert library can have side effects.
const configureHost = require('./configureHost');

const { hostname, ports, ssl } = await configureHost(
Object.assign(customOrigin, {
dir: dirname,
interactive: false
})
);
upwardServerOptions.host = hostname;
upwardServerOptions.https = ssl;
upwardServerOptions.port = envPort || ports.staging || 0;
} catch (e) {
prettyLogger.error(
'Could not configure or access custom host. Using loopback...',
e.message
);
}
}
}

const { createUpwardServer } = require('@magento/upward-js');
prettyLogger.info('Launching UPWARD server\n');
const server = await createUpwardServer(upwardServerOptions);
prettyLogger.success('\nUPWARD server running.');
return server;
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ class UpwardDevServerPlugin {
const oldAfter = devServer.after;
devServer.after = (app, ...rest) => {
if (oldAfter) oldAfter(app, ...rest);
// compression and security middlewares run before upward-js
// but can run after everything else
app.use(upward.bestPractices());
app.use((req, res, next) => this.handleRequest(req, res, next));
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ test('applies to a Webpack compiler and resolves any existing devServer requests
'path/to/upward'
);
devServer.after(app);
const handler = app.use.mock.calls[1][0];
const handler = app.use.mock.calls[0][0];

handler(req, res, next);
expect(upward.IOAdapter.default).not.toHaveBeenCalled();
Expand Down Expand Up @@ -115,7 +115,7 @@ test('shares middleware promise so as not to create multiple middlewares', async
'path/to/upward'
);
devServer.after(app);
const handler = app.use.mock.calls[1][0];
const handler = app.use.mock.calls[0][0];

handler(req, res, next);
handler('some', 'other', 'stuff');
Expand Down Expand Up @@ -155,7 +155,7 @@ test('supplies a dev-mode IOAdapter with webpack fs integration', async () => {
const plugin = new UpwardDevServerPlugin(devServer, process.env);
plugin.apply(compiler);
devServer.after(app);
const handler = app.use.mock.calls[1][0];
const handler = app.use.mock.calls[0][0];
handler();
await plugin.middlewarePromise;

Expand Down Expand Up @@ -209,6 +209,13 @@ test('supplies a dev-mode IOAdapter with webpack fs integration', async () => {
expect.stringMatching(/cFile$/),
'utf8'
);
const fsFail = () => {
throw new Error('Nope, FS failed');
};
compiler.inputFileSystem.readFileSync.mockImplementationOnce(fsFail);
compiler.outputFileSystem.readFileSync.mockImplementationOnce(fsFail);
defaultIO.readFile.mockImplementationOnce(fsFail);
await expect(io.readFile('./missing-file', 'utf8')).rejects.toThrow();
});

test('dev-mode IOAdapter uses fetch', async () => {
Expand All @@ -222,7 +229,8 @@ test('dev-mode IOAdapter uses fetch', async () => {
const plugin = new UpwardDevServerPlugin(devServer, process.env);
plugin.apply({});
devServer.after(app);
const handler = app.use.mock.calls[1][0];

const handler = app.use.mock.calls[0][0];
handler();
await plugin.middlewarePromise;

Expand Down Expand Up @@ -250,7 +258,8 @@ test('dev-mode IOAdapter can fetch unsecure URLs', async () => {
const plugin = new UpwardDevServerPlugin(devServer, process.env);
plugin.apply({});
devServer.after(app);
const handler = app.use.mock.calls[1][0];

const handler = app.use.mock.calls[0][0];
handler();
await plugin.middlewarePromise;

Expand Down
18 changes: 18 additions & 0 deletions packages/pwa-buildpack/lib/cli/serve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const { resolve } = require('path');
const prettyLogger = require('../util/pretty-logger');
const serve = require('../Utilities/serve');

module.exports.command = 'serve <directory>';
module.exports.describe = 'starts a node server in staging mode';

module.exports.handler = async function buildpackCli({ directory }) {
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = 'test';
}

const projectRoot = resolve(directory);
serve(projectRoot).catch(e => {
prettyLogger.error(e.stack);
throw new Error(e.message);
});
};
29 changes: 0 additions & 29 deletions packages/upward-js/lib/bestPractices.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/upward-js/lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module.exports = {
IOAdapter: require('./IOAdapter'),
middleware: require('./middleware'),
bestPractices: require('./bestPractices'),
createUpwardServer: require('./createUpwardServer')
};
Loading