Родитель
6e1a3c09f7
Коммит
f6410554f0
21
README.md
21
README.md
|
@ -42,7 +42,8 @@ Generic scripts that don't need env vars. Use these for development:
|
|||
| Script | Description |
|
||||
|-------------------------|-------------------------------------------------------|
|
||||
| npm run dev:admin | Starts the dev server (admin app) |
|
||||
| npm run dev:amo | Starts the dev server (amo) |
|
||||
| npm run dev:amo | Starts the dev server and proxy (amo) |
|
||||
| npm run dev:amo:no-proxy| Starts the dev server without proxy (amo) |
|
||||
| npm run dev:disco | Starts the dev server (discovery pane) |
|
||||
| npm run eslint | Lints the JS |
|
||||
| npm run stylelint | Lints the SCSS |
|
||||
|
@ -94,6 +95,24 @@ To see this report while running tests locally, type:
|
|||
|
||||
open ./coverage/index.html
|
||||
|
||||
### Running AMO for local development
|
||||
|
||||
A proxy server is provided for running the AMO app with the API on the same host as the frontend.
|
||||
This provides a setup that is closer to production than running the frontend on its own. The
|
||||
default configuration for this is to use a local addons-server for the API which can be setup
|
||||
according to the
|
||||
[addons-server docs](https://addons-server.readthedocs.io/en/latest/topics/install/index.html).
|
||||
Docker is the preferred method of running addons-server.
|
||||
|
||||
Authentication will work when initiated from addons-frontend and will persist to addons-server but
|
||||
it will not work when logging in from an addons-server page. See
|
||||
[mozilla/addons-server#4684](https://github.com/mozilla/addons-server/issues/4684) for more
|
||||
information on fixing this.
|
||||
|
||||
If you would like to use `https://addons-dev.allizom.org` for the API you should use the
|
||||
`npm run dev:amo:no-proxy` command with an `API_HOST` to start the server without the proxy. For
|
||||
example: `API_HOST=https://addons-dev.allizom.org npm run dev:amo:no-proxy`.
|
||||
|
||||
### Configuring for local development
|
||||
|
||||
The `dev` scripts above will connect to a hosted development API by default.
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
require('babel-register');
|
||||
|
||||
const http = require('http');
|
||||
|
||||
const bunyan = require('bunyan');
|
||||
const config = require('config');
|
||||
const cookie = require('cookie');
|
||||
const httpProxy = require('http-proxy');
|
||||
|
||||
const log = bunyan.createLogger({
|
||||
name: 'proxy',
|
||||
app: config.get('appName'),
|
||||
serializers: bunyan.stdSerializers,
|
||||
});
|
||||
|
||||
const proxy = httpProxy.createProxyServer();
|
||||
const apiHost = config.get('proxyApiHost', null) || config.get('apiHost');
|
||||
const frontendHost = `http://${config.get('serverHost')}:${config.get('serverPort')}`;
|
||||
|
||||
log.info(`apiHost: ${apiHost}`);
|
||||
log.info(`frontendHost: ${frontendHost}`);
|
||||
|
||||
const array = (value) => {
|
||||
if (!value) {
|
||||
return [];
|
||||
} else if (Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
return [value];
|
||||
};
|
||||
|
||||
function unsecureCookie(req, res, proxyRes) {
|
||||
const proxyCookies = array(proxyRes.headers['set-cookie']);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
proxyRes.headers['set-cookie'] = proxyCookies.map((rewrittenCookie) => {
|
||||
if (!req.connection.encrypted) {
|
||||
return rewrittenCookie.replace(/;\s*?(Secure)/i, '');
|
||||
}
|
||||
return rewrittenCookie;
|
||||
});
|
||||
}
|
||||
|
||||
function getHost(req) {
|
||||
const useDesktop = req.headers.cookie && cookie.parse(req.headers.cookie).mamo === 'off';
|
||||
if (useDesktop || req.url.startsWith('/api/')) {
|
||||
return apiHost;
|
||||
}
|
||||
return frontendHost;
|
||||
}
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
const host = getHost(req);
|
||||
return proxy.web(req, res, {
|
||||
target: host,
|
||||
changeOrigin: true,
|
||||
autoRewrite: true,
|
||||
protocolRewrite: 'http',
|
||||
cookieDomainRewrite: '',
|
||||
});
|
||||
});
|
||||
|
||||
proxy.on('proxyRes', (proxyRes, req, res) => {
|
||||
log.info(`${proxyRes.statusCode} ~> ${getHost(req)}${req.url}`);
|
||||
unsecureCookie(req, res, proxyRes);
|
||||
});
|
||||
|
||||
proxy.on('error', (error, req, res) => {
|
||||
log.error(`ERR ~> ${getHost(req)}${req.url} ${error}`);
|
||||
res.writeHead(500, { 'Content-type': 'text/plain' });
|
||||
res.end('Proxy error');
|
||||
});
|
||||
|
||||
const port = parseInt(config.get('proxyPort', '3333'), 10);
|
||||
log.info(`🚦 Proxy running at http://localhost:${port}`);
|
||||
server.listen(port);
|
|
@ -1,5 +1,8 @@
|
|||
{
|
||||
"apiHost": "API_HOST",
|
||||
"proxyApiHost": "PROXY_API_HOST",
|
||||
"proxyEnabled": "PROXY_ENABLED",
|
||||
"proxyPort": "PROXY_PORT",
|
||||
"serverHost": "SERVER_HOST",
|
||||
"serverPort": "SERVER_PORT",
|
||||
"staticHost": "STATIC_HOST",
|
||||
|
|
|
@ -173,4 +173,6 @@ module.exports = {
|
|||
defaultClientApp: 'firefox',
|
||||
|
||||
fxaConfig: null,
|
||||
|
||||
proxyEnabled: false,
|
||||
};
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
module.exports = {
|
||||
apiHost: 'http://localhost:3000',
|
||||
proxyApiHost: 'http://olympia.dev',
|
||||
proxyPort: 3000,
|
||||
proxyEnabled: true,
|
||||
fxaConfig: 'local',
|
||||
};
|
||||
|
|
21
package.json
21
package.json
|
@ -10,6 +10,7 @@
|
|||
"clean": "rimraf './dist/*!(.gitkeep)' './webpack-assets.json'",
|
||||
"dev:admin": "better-npm-run dev:admin",
|
||||
"dev:amo": "better-npm-run dev:amo",
|
||||
"dev:amo:no-proxy": "better-npm-run dev:amo:no-proxy",
|
||||
"dev:disco": "better-npm-run dev:disco",
|
||||
"eslint": "eslint .",
|
||||
"stylelint": "stylelint --syntax scss **/*.scss",
|
||||
|
@ -38,11 +39,18 @@
|
|||
}
|
||||
},
|
||||
"dev:amo": {
|
||||
"command": "better-npm-run start-dev",
|
||||
"command": "better-npm-run start-dev-proxy",
|
||||
"env": {
|
||||
"NODE_APP_INSTANCE": "amo"
|
||||
}
|
||||
},
|
||||
"dev:amo:no-proxy": {
|
||||
"command": "better-npm-run start-dev",
|
||||
"env": {
|
||||
"NODE_APP_INSTANCE": "amo",
|
||||
"PROXY_ENABLED": "false"
|
||||
}
|
||||
},
|
||||
"dev:disco": {
|
||||
"command": "better-npm-run start-dev",
|
||||
"env": {
|
||||
|
@ -64,6 +72,15 @@
|
|||
"NODE_PATH": "./:./src"
|
||||
}
|
||||
},
|
||||
"start-dev-proxy": {
|
||||
"command": "npm run clean && concurrently --kill-others 'npm run webpack-dev-server' 'node bin/server.js | bunyan' 'node bin/proxy.js | bunyan'",
|
||||
"env": {
|
||||
"ENABLE_PIPING": "true",
|
||||
"NODE_ENV": "development",
|
||||
"NODE_PATH": "./:./src",
|
||||
"SERVER_PORT": "3333"
|
||||
}
|
||||
},
|
||||
"servertest": {
|
||||
"command": "mocha --compilers js:babel-register --timeout 10000 tests/server/",
|
||||
"env": {
|
||||
|
@ -215,6 +232,7 @@
|
|||
"chalk": "1.1.3",
|
||||
"cheerio": "0.22.0",
|
||||
"concurrently": "3.3.0",
|
||||
"cookie": "0.3.1",
|
||||
"css-loader": "0.26.1",
|
||||
"deepcopy": "0.6.3",
|
||||
"eslint": "3.14.1",
|
||||
|
@ -225,6 +243,7 @@
|
|||
"fetch-mock": "5.9.3",
|
||||
"file-loader": "0.10.0",
|
||||
"glob": "7.1.1",
|
||||
"http-proxy": "1.16.2",
|
||||
"json-loader": "0.5.4",
|
||||
"karma": "1.4.1",
|
||||
"karma-chai": "0.1.0",
|
||||
|
|
|
@ -26,7 +26,7 @@ export default (
|
|||
<Route path=":visibleAddonType/categories/" component={CategoryList} />
|
||||
<Route path=":visibleAddonType/featured/" component={FeaturedAddons} />
|
||||
<Route path=":visibleAddonType/:slug/" component={CategoryPage} />
|
||||
<Route path="fxa-authenticate" component={HandleLogin} />
|
||||
<Route path="/api/v3/accounts/authenticate/" component={HandleLogin} />
|
||||
<Route path="search/" component={SearchPage} />
|
||||
<Route path="401/"
|
||||
component={config.get('isDevelopment') ? NotAuthorized : NotFound} />
|
||||
|
|
|
@ -322,12 +322,23 @@ export function runServer({
|
|||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
log.info(oneLine`🔥 Addons-frontend server is running [ENV:${env}]
|
||||
[APP:${app}] [isDevelopment:${isDevelopment}
|
||||
[isDeployed:${isDeployed}] [apiHost:${config.get('apiHost')}]
|
||||
[apiPath:${config.get('apiPath')}]`);
|
||||
log.info(
|
||||
`👁 Open your browser at http://${host}:${port} to view it.`);
|
||||
const proxyEnabled = convertBoolean(config.get('proxyEnabled'));
|
||||
// Not using oneLine here since it seems to change ' ' to ' '.
|
||||
log.info([
|
||||
`🔥 Addons-frontend server is running [ENV:${env}] [APP:${app}]`,
|
||||
`[isDevelopment:${isDevelopment}] [isDeployed:${isDeployed}]`,
|
||||
`[apiHost:${config.get('apiHost')}] [apiPath:${config.get('apiPath')}]`,
|
||||
].join(' '));
|
||||
if (proxyEnabled) {
|
||||
const proxyPort = config.get('proxyPort');
|
||||
log.info(
|
||||
`🚦 Proxy detected, frontend running at http://${host}:${port}.`);
|
||||
log.info(
|
||||
`👁 Open your browser at http://localhost:${proxyPort} to view it.`);
|
||||
} else {
|
||||
log.info(
|
||||
`👁 Open your browser at http://${host}:${port} to view it.`);
|
||||
}
|
||||
return resolve(server);
|
||||
});
|
||||
} else {
|
||||
|
|
Загрузка…
Ссылка в новой задаче