version: '3.2'
networks:
backend-network:
driver: bridge
frontend-network:
driver: bridge
volumes:
redis-data:
pg-data:
home-dir:
services:
&app-service app: &app-service-template
build:
context: ./docker/app
dockerfile: Dockerfile
user: '${USER_ID:-1000}:${GROUP_ID:-1000}'
volumes:
- /etc/passwd:/etc/passwd:ro
- /etc/group:/etc/group:ro
- ./src:/app:rw
- home-dir:/home/user
hostname: *app-service
environment:
REDIS_HOST: redis
REDIS_PORT: &redis-port 6379
DB_HOST: postgres
DB_PORT: &pg-port 5432
DB_DATABASE: &pg-db-name app
DB_USERNAME: &pg-username forge
DB_PASSWORD: &pg-password secret
SCHEDULE_PERIOD: 60
FPM_PORT: &php-fpm-port 9000
FPM_USER: '${USER_ID:-1000}'
FPM_GROUP: '${GROUP_ID:-1000}'
APP_ENV: local
APP_DEBUG: 'true'
HOME: /home/user
command: keep-alive.sh
depends_on:
- redis
- postgres
networks:
- backend-network
&queue-service queue:
<<: *app-service-template
restart: always
hostname: *queue-service
command: php /app/artisan queue:work
&scheduler-service scheduler:
<<: *app-service-template
restart: always
hostname: *scheduler-service
command: scheduler.sh 'php /app/artisan schedule:run'
&php-fpm-service php-fpm:
<<: *app-service-template
user: 'root:root'
restart: always
hostname: *php-fpm-service
ports: [*php-fpm-port]
entrypoint: /fpm-entrypoint.sh
command: php-fpm --nodaemonize -d 'opcache.enable=0' -d 'display_startup_errors=On' -d 'display_errors=On' -d 'error_reporting=E_ALL'
networks:
- backend-network
- frontend-network
&node-service node:
image: 'node:alpine'
working_dir: /app
hostname: *node-service
volumes:
- ./src:/app
expose:
- '8081'
nginx:
build:
context: ./docker/nginx
dockerfile: Dockerfile
restart: always
working_dir: /usr/share/nginx/html
environment:
FPM_HOST: *php-fpm-service
FPM_PORT: *php-fpm-port
ROOT_DIR: '/app/public' # App path must equals with php-fpm container path
volumes:
- ./src:/app:ro
ports:
- '9999:80'
- '8081:8081'
depends_on:
- *php-fpm-service
networks:
- frontend-network
redis:
image: redis:4.0.11-alpine
restart: always
command: redis-server
volumes:
- redis-data:/data:rw
ports: [*redis-port, '16379:6379'] # Port 16379 for connecting from localhost
networks:
- backend-network
postgres:
image: postgres:9.6.10-alpine
restart: always
environment:
POSTGRES_DB: *pg-db-name
POSTGRES_USER: *pg-username
POSTGRES_PASSWORD: *pg-password
volumes:
- pg-data:/var/lib/postgresql/data:rw
ports: [*pg-port, '15432:5432'] # Port 15432 for connecting from localhost using, for example, data-grip
networks:
- backend-network
ℹ 「wds」: Project is running at https://localhost:8081/
ℹ 「wds」: webpack output is served from https://localhost:8081/
const path = require('path');
// variables
const isProduction = process.argv.indexOf('production') >= 0;
const sourcePath = path.join(__dirname, './resources');
const outPath = path.join(__dirname, './public');
const hostPort = 8081;
// plugins
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const WebpackCleanupPlugin = require('webpack-cleanup-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
context: sourcePath,
entry: {
main: ['./app.tsx'],
},
optimization: {
minimizer: isProduction ? [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})] : [],
},
output: {
path: outPath,
filename: 'js/app.js',
chunkFilename: '[chunkhash].js',
publicPath: isProduction ? '/' : `https://localhost:${hostPort}/`,
},
target: 'web',
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx'],
// Fix webpack's default behavior to not load packages with jsnext:main module
// (jsnext:main directs not usually distributable es6 format, but es6 sources)
mainFields: ['module', 'browser', 'main'],
alias: {
app: path.resolve(__dirname, 'resources/'),
components: path.resolve(__dirname, 'resources/components/'),
types: path.resolve(__dirname, 'resources/types/'),
'react-dom': '@hot-loader/react-dom',
},
},
module: {
rules: [
{
test: [/\.tsx?$/, /\.ts?$/],
use: [
{
loader: 'awesome-typescript-loader',
options: {
useCache: true,
useBabel: true,
babelOptions: {
babelrc: true,
},
},
},
],
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'postcss-loader', 'sass-loader'],
}),
},
{ test: [/\.png$/, /\.svg$/], use: 'url-loader?limit=10000' },
{ test: /\.jpg$/, use: 'file-loader' },
],
},
plugins: [
new WebpackCleanupPlugin({
exclude: ['.htaccess', 'favicon.ico', 'index.php', 'robots.txt'],
}),
new ExtractTextPlugin({
filename: 'css/app.css',
disable: !isProduction,
}),
new BundleAnalyzerPlugin({
analyzerMode: (isProduction ? 'server' : 'disabled'),
}),
],
devServer: {
contentBase: sourcePath,
hot: true,
inline: true,
host: 'localhost',
port: hostPort,
https: true,
headers: { 'Access-Control-Allow-Origin': '*' },
watchOptions: {
exclude: [/node_modules/],
},
historyApiFallback: {
disableDotRule: true,
},
stats: 'minimal',
},
devtool: 'cheap-module-eval-source-map',
node: {
fs: 'empty',
net: 'empty',
},
};
GET https://localhost:8081/js/app.js net::ERR_CONNECTION_RESET