#php #webpack #proxy #localhost #remote-server
Вопрос:
Я уже некоторое время борюсь с проблемой:
Я хотел бы иметь локальную среду разработки webpack/encore с HMR (замена горячих модулей), которая использует индексный файл, созданный сервером (из Contao-CMS/PHP/MySQL).
Подробно:
У меня есть удаленный сервер, доступный по протоколу HTTPS (порт 443). Я использую пакет управляемого хостинга, поэтому, к сожалению, я не могу запустить сервер webpack на альтернативном порту, мне приходится придерживаться портов 80 и 443.
На этом удаленном сервере работает база данных MySQL и PHP (Composer). Содержимое страницы управляется CMS Contao.
Этот удаленный сервер генерирует структуру PHP/HTML/DOM и данные/содержимое.
У меня также есть локальная среда программирования с Webpack, Encore и моими стилями/javascripts. Я не хочу дублировать свою текущую удаленную установку Contao/MySQL там. Я бы предпочел получить структуру с удаленного сервера для использования в моей локальной среде.
Моей любимой настройкой была бы:
Удаленный сервер доступен под https://myserver.de:443
(Порт 443, HTTPS, построен npm run build
, работает стабильно, общедоступен)
Локальный сервер работает под https://localhost:443 (самозаверяющий) для разработки новых стилей/скриптов: он должен взять все с удаленного сервера (HTML-код/структура/дом, скрипты, изображения, контент), но и обслуживать локальные стили/макетов/скриптов и активировать горячая замена модуля (ГРМ) для автоматической перезагрузки на изменения. В принципе, я хотел бы редактировать/переписывать свой стиль в реальном времени, используя фреймворк (и содержимое) с существующей удаленной страницы.
Моя проблема в том, что:
Это должно быть управляемо с помощью прокси-сервера.
Однако обычно вы просто отправляете API-запрос, чтобы получить только данные с удаленного сайта.
На локальном хосте (обычно) у вас есть индекс(.html/php), сценарии/стили и все остальное, и вы получаете только данные/контент через прокси-запрос API.
В моей любимой настройке это не работает. Структура и содержимое включены в мой (PHP/MySQL/Contao, сгенерированный и шаблонизированный) index.php, и здесь должны быть введены правильные стили/скрипты/HMR с локального хоста. (какой веб-пакет должен быть готов из коробки)
Так что, в принципе, я должен запросить/загрузить/прокси-сервер index.php с удаленного сервера и внедрите туда мои стили/скрипты webpack/encore, чтобы внести изменения в стиль и работать с HMR.
Мой план таков:
- прокси-сервер все с удаленного сервера, кроме /layout/ (где хранятся сгенерированные на бис стили/скрипты)
- скачать/прокси-сервер index.php (сгенерированная сервером корневая страница со всей структурой из шаблонов Contao-CMS, данными из базы данных MySQL и ссылками на скрипты/стили) из https://myserver.de
- Webpack должен «как-то» заменить файлы стилей/сценариев (начиная с /layout/ in index.php) и добавьте скрипт HMR и доставьте его как корневую страницу с https://localhost
- На https://localhost, структура HTML/DOM/Данных/шаблонов с удаленного сервера доставляется, но стиль и сценарии (/макет/) из локальной среды используются и динамически перезагружаются HMR.
This can’t be this difficult, can it? I assumed that this (server-proxy-localhost-thing) would be a quite common application of Webpack/Encore with HMR?
What I’ve tried so far:
- I managed to make a dev-server on localhost
npm run local
and a second dev-server on remotenpm run server
. The server at https://mydomain.de loads the /layout/ files from the local server https://localhost:443/layout/. When saving local files, they are instantly uploaded to the remote server. Both webpack servers are rebuilt and the HMR on https://mydomain.de is reloaded. Yes, this is ugly, and yes, it works! However, if anybody NOT using the local webpack server wants to view the page, the styles can’t be loaded (as loading from https://localhost:443/layout of course leads to a timeout). - I managed to proxy everything (except /layout/) to localhost. On the root page (/), I disabled compression (otherwise, gzip would lead to problems, even when using the new
onProxyRes: responseInterceptor()
function fromhttp-proxy-middleware
, which still seems a bit buggy to me). Then, I am able to regex-replace the files from https://mydomain.de/layout/xyz.hexcode.css to https://localhost/layout/xyz.css. However, webpack generates (and combines) the files dynamically and I can’t be sure if the xyz files have exact counterparts on localhost. Also, I did not yet manage to inject the HMR code.
But «somehow» this must be achieved easier without manually «searchamp;replace»? Webpack/Encore/HMR already know which files are needed, so they «somehow» should just inject them into the (proxied/downloaded) root page!?
What am I missing?
My files:
part of index.php from https://myserver.de
<!-- these layouts/scripts are from Contao and not served via Webpack/Encore -->
<link rel="stylesheet" href="assets/css/layout.min.css,responsive.min.css,colorbox.min.css,tablesorter.m...-0568d07b.css">
<script src="assets/js/jquery.min.js-55e8b57b.js"></script>
<!-- these layout/scripts are generated via Encore and should be served lokally with HMR -->
<link rel="stylesheet" href="/layout/css/base.a195259b3b6d1c0ea116.css">
<link rel="stylesheet" href="/layout/css/3.c051ea961ca07ebe9603.css">
<link rel="stylesheet" href="/layout/css/fonts.1cad325240e751e2982a.css">
<link rel="stylesheet" href="/layout/css/news.25dbe26df9e81062227b.css">
<link rel="stylesheet" href="/layout/css/player.ab38e835c60a5569740b.css">
<link rel="stylesheet" href="/layout/css/nav.bae121a49552892e1ec9.css">
<link rel="stylesheet" href="/layout/css/search.424f2d130fdf3fc848dd.css">
<link rel="stylesheet" href="/layout/css/image.8f8b30f024d7de8ae5dd.css">
<link rel="stylesheet" href="/layout/css/accordion.3167aff65e6d694465f3.css">
<link rel="stylesheet" href="/layout/css/lyrics_chords.b7c98d9b5fe8443510de.css">
<script src="/layout/js/runtime.de3cb55993caa785606e.js"></script>
<script src="/layout/js/0.68475f916dd09a70f2ed.js"></script>
<script src="/layout/js/1.b0717b92f1874e527d29.js"></script>
<script src="/layout/js/base.5b6ff652693c4338465a.js"></script>
<script src="/layout/js/3.a860c6c3271280c8338d.js"></script>
<script src="/layout/js/fonts.fd828da43496442d0bd4.js"></script>
<link rel="stylesheet" href="/layout/css/code.59f6e92a9deeff93d3c4.css">
<script src="/layout/js/nav.f5f43f643bacbe9a2b0f.js"></script>
part of package.json:
"https": {
"cert": "key/private.pem",
"key": "key/private.key",
"port": "443"
},
"scripts": {
"local": "encore dev-server --hot --watch --disable-host-check --https --port 443 --cert key/private.pem --key key/private.key",
"server": "encore dev-server --hot --watch --disable-host-check --host localhost --https --port 443",
"dev": "encore dev-server --hot --disable-host-check --host localhost --proxy https://mydomain.de",
"build": "encore production --progress --profile",
... and some other test scripts
... and lots of dependencies
},
(unfortunately, —https, —cert and —key have to be added explicitely by CLI. Otherwise, it tries to load the /layout/ — files via HTTP. But let’s concentrate on npm run dev
here)
(very small) part of webpack.config.js
Encore
.setOutputPath("web/layout/")
.setPublicPath("/layout")
.addEntry("base", "./src/assets/config/base.js")
.addEntry("fonts", "./src/assets/config/fonts.js")
.addEntry("code", "./src/assets/config/code.js")
...
.configureDevServerOptions((options) => {
//options.http2 = true;
options.port = process.env.npm_package_https_port;
options.https = {
key: process.env.npm_package_https_key,
cert: process.env.npm_package_https_cert,
};
options.compress = true;
options.hot = true;
options.publicPath = "./web";
options.public = "https://localhost:443"; //process.env.npm_package_remote_proxy;
options.historyApiFallback = true;
//options.injectHot = true;
//options.inline = false;
options.index = "index.php";
options.writeToDisk = true;
// if proxy is activated: build proxy (does not work correctly: HMR is not injected)
if (process.env.npm_lifecycle_script.match(/--proxy ([^ ] )/)) {
const proxy = process.env.npm_lifecycle_script.match(/--proxy ([^ ] )/)[1];
options.proxy = [
{
target: proxy,
changeOrigin: true,
context: (pathname, req) => {
// Proxy everything except layout
if (pathname.startsWith("/layout/")) return false;
return true;
},
onProxyReq: (proxyReq, req, res) => {
if (req.url === "/") {
// turn off compression
proxyReq.setHeader("accept-encoding", "identity");
}
},
onProxyRes: (proxyRes, req, res) => {
let originalBody = Buffer.from([]);
proxyRes.on("data", (data) => {
originalBody = Buffer.concat([originalBody, data]);
});
proxyRes.on("end", () => {
let bodyString = originalBody.toString("utf8");
if (req.url === "/") {
var proxyRegex = new RegExp(proxy, "g");
bodyString = bodyString.replace(proxyRegex,"https://localhost");
bodyString = bodyString.replace(/(/layout/(. ?))(.[a-f0-9] ?)(.(js|css))/g,"$1$4");
bodyString = bodyString.replace(/hello/g, "Goodbye");
}
//console.log(newBody);
res.set({
"content-type": "text/html; charset=utf-8",
//"content-encoding": "gzip",
});
//res.write(zlib.gzipSync(newBody));
res.write(bodyString);
res.end();
});
},
selfHandleResponse: true,
},
];
}
options.progress = true;
})
.enableBuildNotifications(false)
.copyFiles([
{
from: "./src/assets/fonts",
to: "./fonts/[path][name].[ext]",
},
{
from: "./src/assets/vendor",
to: "./vendor/[path][name].[ext]",
},
])
... and other Encore-Related stuff with generating Favicons, Versioning, Stats, Filenames, converting SCSS to CSS, etc.