2

I would like to do a Hot-Deployment of the Front-End-Code (HTML, CSS, JS) of some Portlet so development time can be saved and not the whole Portlet needs to be redeployed.

The Portlet is a .war File.

In the good old Liferay 6.2 this was simply possible by overwriting the static frontend Code in the tomcat/webapps/portlet-name directory. In Liferay DXP this is no longer possible, since the Portlet is not extracted to tomcat/webapps/ anymore.

Is there any possibility for a frontend-Hot-Deploy, so i can change e.g. my .html file on the fly and I don't have to redeploy the whole .war Portlet?

Philipp Hellmayr
  • 312
  • 2
  • 11

2 Answers2

1

Apart from the described method being really bad practice for maintenance, I'm wondering how much time you actually save (as you say that this is your motivation).

You can always implement your portlet to include various resources from places outside of Liferay's control, but naturally, the provided tools won't help you keeping everything in sync - that'll be your personal problem to solve.

By the way: Tomcat's mode, in which you are able to just replace random content in the webapps directory, is called development mode.

Olaf Kock
  • 46,930
  • 8
  • 59
  • 90
  • It would be a big time saver for local development and it saved us (~50 developers) for sure a lot of time to use some script for this in LR 6.2. So i guess there is no possibility to edit the .html Files directly in the new LR anymore? Thanks a lot for your help :) – Philipp Hellmayr Jun 17 '19 at 13:12
  • I'm not aware of anything directly in Liferay. As I said: You're not limited to load your HTML and other files from within Liferay (at least at development time that might make sense). You could deploy them in a webapp as before and just reference these other locations from your portlet code. – Olaf Kock Jun 17 '19 at 14:15
1

We found an alternative solution to improve our time for frontend development, but it works completly different as it did in the old Liferay 6.2.

Basically we use an express.js proxy Server, which runs in parallel to Liferay on some different Port. This Proxy Server forwards all the requests to the other running liferay, except the requests for HTML, CSS and JS Files. Those are directly served from the local file System instead. Also an automatic rebuild of the frontend is triggered when a HTML, CSS or JS File is changed and saved.

This small Proxy-Server consists basically out of those two Files:

The dev-server.js File:

const packageConfig = require('../../../package.json');
const projectName = packageConfig.name;

const config = Object.assign({}, {
    port: 8088,
    liferayUrl: 'http://localhost:8080',
    liferayVersion: 7,
    webpackConfigFile: './webpack.development.config.js',
}, packageConfig.devServer || {});

const path = require('path');
const webpack = require('webpack');
const middleware = require('webpack-dev-middleware');
const webpackCompiler = webpack(require(config.webpackConfigFile));
const express = require('express');
const app = express();

const httpProxy = require('http-proxy');
const liferayProxy = httpProxy.createProxyServer();

let publicPath = `/o/${projectName}/static/js/`;
if(config.liferayVersion === 6) {
    publicPath = `/${projectName}/static/js/`
}

app.use(
    middleware(webpackCompiler, {
        publicPath: `/o/${projectName}/static/js/`
    })
);

app.all('/*', function(req, res) {
    liferayProxy.web(req, res, {target: config.liferayUrl});
});

app.listen(config.port, () => console.log('Development server listening on port ' + config.port + '!'));

And the package.json:

{
  "name": "react-base",
  "version": "1.0.0",
  "license": "NOLICENSE",
  "private": true,
  "scripts": {
    "preinstall": "node ./target/ui-build/build/preInstallHook.js",
    "build-dev": "gulp --gulpfile ./target/ui-build/build/gulpfile.js && webpack --config ./target/ui-build/build/webpack.development.config.js --progress --profile",
    "build": "gulp --gulpfile ./target/ui-build/build/gulpfile.js production && webpack --config ./target/ui-build/build/webpack.production.config.js --bail",
    "lint": "eslint -c ./target/ui-build/build/.eslintrc.js --rulesdir \"node_modules/@myproject/react-component-lib/eslint-rules/\"  \"src/main/react/**/*.js\" ",
    "test": "jest --config=./target/ui-build/build/jest.config.js --rootDir=./ --passWithNoTests",
    "coverage": "jest --config=./target/ui-build/build/jest.config.js --rootDir=./ --passWithNoTests --coverage",
    "stats": "webpack-bundle-analyzer ./target/generated-sources/js/stats.json",
    "start:dev": "node ./target/ui-build/build/dev-server.js"
  },
  "dependencies": {
    "@babel/runtime": "^7.0.0",
    "mobx": "3.1.16",
    "mobx-react": "4.4.3",
    "prop-types": "15.7.2",
    "react": "16.8.4",
    "react-dom": "16.8.4"
  },
  "devDependencies": {
    "autoprefixer": "^9.1.5",
    "babel-core": "^7.0.0-bridge.0",
    "@babel/core": "7.1.0",
    "babel-eslint": "10.0.1",
    "babel-jest": "^23.0.0",
    "babel-loader": "8.0.4",
    "@babel/plugin-proposal-class-properties": "7.1.0",
    "@babel/plugin-proposal-decorators": "7.1.0",
    "@babel/plugin-proposal-object-rest-spread": "7.0.0",
    "@babel/plugin-transform-runtime": "7.1.0",
    "@babel/preset-env": "7.1.0",
    "@babel/preset-react": "7.0.0",
    "css-loader": "1.0.0",
    "enzyme": "3.4.0",
    "enzyme-adapter-react-16": "1.5.0",
    "eslint": "4.19.1",
    "eslint-plugin-jsx-a11y": "6.0.3",
    "eslint-plugin-react": "7.11.1",
    "express": "4.17.1",
    "file-loader": "2.0.0",
    "fs-extra": "7.0.0",
    "gulp": "3.9.1",
    "gulp-concat": "2.6.1",
    "http-proxy": "1.17.0",
    "identity-obj-proxy": "3.0.0",
    "jest": "^23.0.0",
    "jest-cli": "^23.0.0",
    "node-sass": "4.9.3",
    "postcss-loader": "3.0.0",
    "raf": "3.4.1",
    "react-test-renderer": "16.8.4",
    "run-sequence": "1.2.2",
    "sass-loader": "7.1.0",
    "style-loader": "0.23.1",
    "url-loader": "1.1.2",
    "url-search-params-polyfill": "5.0.0",
    "webpack": "4.20.2",
    "webpack-bundle-analyzer": "^3.0.2",
    "webpack-cli": "^3.1.1",
    "webpack-dev-middleware": "3.7.0"
  },
  "sideEffects": [
    "*.css",
    "*.scss"
  ]
}

The Proxy-Server can be started by calling 'yarn run start:dev', then you can access Liferay over the Proxy-Server via http://localhost:8088

Philipp Hellmayr
  • 312
  • 2
  • 11
  • Sounds like a creative workaround. And like something that'd be awesome to have on https://liferay.dev/blogs - if you have a liferay.com account, you should be able to submit an article there, otherwise I can help you get the permissions. – Olaf Kock Jun 19 '19 at 13:31