How to automatically build CSS inside a ddev project using node-sass scss in a sidecar container? - ddev

I have a Drupal project where I would like to use Node.js build scripts to compile SCSS into CSS.

I use a separate sidecar container that constantly watches for changes to SCSS in my Drupal theme and builds the CSS.
I have a .ddev/docker-compose.sass-watch.yaml file with the following:
version: "3.6"
services:
sass-watch:
container_name: ddev-${DDEV_SITENAME}-sass-watch
image: node:12
user: $DDEV_UID:$DDEV_GID
labels:
com.ddev.site-name: ${DDEV_SITENAME}
com.ddev.approot: $DDEV_APPROOT
volumes:
- type: bind
source: ../drupal/web/themes/custom/MY_THEME
target: /app
consistency: cached
- ".:/mnt/ddev_config:ro"
working_dir: /app
command: ["sh", "-c", "npm i && npm run watch"]
Then inside my theme directory I have a package.json as follows:
{
"name": "MY_THEME",
"scripts": {
"build": "node-sass scss -o css --output-style compressed",
"watch": "node-sass scss -o css --output-style compressed --source-map true -w"
},
"dependencies": {
"node-sass": "^4.14.1"
}
}
The watch command runs permanently in the background while my ddev project is running.
I can also use ddev logs -s sass-watch to get the output from the watch command if the build doesn't look like it has worked for some reason.

node-sass is no longer maintained and has an issue where it doesn't pick up new filenames while watching. Here's an updated version of Dave's answer that uses the more current "dart sass":
docker-composer.*.yaml
version: "3.8"
services:
sass-watch:
container_name: ddev-${DDEV_SITENAME}-sass-watch
image: node:12
user: $DDEV_UID:$DDEV_GID
labels:
com.ddev.site-name: ${DDEV_SITENAME}
com.ddev.approot: $DDEV_APPROOT
volumes:
- type: bind
source: ../drupal/web/themes/custom/MY_THEME
target: /app
- ".:/mnt/ddev_config:ro"
working_dir: /app
command: [ "sh", "-c", "npm i && npm run watch" ]
package.json
{
"name": "MY_THEME",
"scripts": {
"build": "sass scss css",
"watch": "sass scss:css -w"
},
"dependencies": {
"sass": "^1.49.8"
}
}
You can, of course, tweak package.json as needed.

Related

PHP Fatal error on CI/CD run php artisan test

I use docker-compose with laravel and postgresql and all works fine in local system. The problem is in the CI/CD.
I have changed the CI/CD yml file over and over but I am stuck!
CI/CD
name: CI/CD
on:
pull_request:
branches: ['master']
push:
branches: ['master']
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: shivammathur/setup-php#v2
with:
php-version: '7.4'
- uses: actions/checkout#v2
- name: Run Containers
run: docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# - name: Run composer install
# run: cd companyname_app_dir && composer install
# - name: Run composer update
# run: cd companyname_app_dir&& composer update
# - name: Setup Project
# run: |
# cd companyname_app_dir
# composer update
# composer install
# php artisan config:clear
# php artisan cache:clear
- name: Run test
run: cd companyname_app_dir && php artisan test
env:
APP_KEY: base64:x06N/IsV5iJ+R6TKlr6sC6Mr4riGgl8Rg09XHHnRZQw=
APP_ENV: testing
DB_CONNECTION: companyname-postgres
DB_DATABASE: db_test
DB_USERNAME: root
DB_PASSWORD: 1234
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action#v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action#v2
- name: Login to Docker Hub
uses: docker/login-action#v2
with:
username: secret
password: secret
- name: Build and push
uses: docker/build-push-action#v3
with:
push: true
file: ./companyname_app_dir/Dockerfile
tags: company_image:latest
build-args: |
"NODE_ENV=production"
There are line comments, I tried using these but I couldn't run a test successfully.
docker-compose
version: '3'
networks:
companyname_network:
driver: bridge
services:
nginx:
image: nginx:stable-alpine
container_name: companyname-nginx
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
restart: always
depends_on:
- companyname_app
networks:
- companyname_network
companyname_app:
restart: 'always'
image: 'companyname_laravel'
container_name: companyname-app
build:
context: .
dockerfile: ./Dockerfile
networks:
- companyname_network
depends_on:
- companyname_db
companyname_db:
image: 'companyname_multiple_db'
container_name: companyname-postgres
build:
context: .
dockerfile: ./DockerfileDB
restart: 'always'
volumes:
- local_pgdata:/docker-entrypoint-initdb.d
environment:
- POSTGRES_MULTIPLE_DATABASES=db,db_test
- POSTGRES_USER=root
- POSTGRES_PASSWORD=1234
ports:
- 15432:5432
networks:
- companyname_network
companyname_dbadmin:
image: adminer
container_name: companyname-dbadmin
restart: 'always'
depends_on:
- companyname_db
ports:
- 5051:8080
networks:
- companyname_network
volumes:
local_pgdata:
docker-compose.dev
version: '3'
services:
nginx:
ports:
- 9000:80
companyname_app:
build:
args:
- NODE_ENV=development
volumes:
- ./companyname_app_dir:/app
- /app/vendor
With this file, I get an error:
Run cd companyname_app_dir && php artisan test
PHP Warning: require(/home/runner/work/companyname_app/companyname_app /companyname_app_dir/vendor/autoload.php): failed to open stream: No such file or directory in /home/runner/work/companyname_app/companyname_app/companyname_app_dir/artisan on line 18
PHP Fatal error: require(): Failed opening required '/home/runner/work/companyname_app/companyname_app/companyname_app_dir/vendor/autoload.php' (include_path='.:/usr/share/php') in /home/runner/work/companyname_app/companyname_app/companyname_app_dir/artisan on line 18
Error: Process completed with exit code 255.
if I use:
- name: Run composer install
run: cd companyname_app_dir && composer install
- name: Run composer update
run: cd companyname_app_dir && composer update
In CI/CD yml and remove Run Containers part, composer install and update successfully, but php artisan test throws this error:
postgresql can not connect
You must use composer install, else you will have no vendor folder at all, so you have nothing to run. That is why you are getting an error if you don't run composer install
You should not run composer update, because you are updating packages to new versions, you never do that in production, you just run composer install --no-dev
You are mixing running docker with a command OUTSIDE the docker container.
Related to point 3., if you are using docker-compose, you cannot execute:
- name: Run test
run: cd companyname_app_dir && php artisan test
env:
APP_KEY: base64:x06N/IsV5iJ+R6TKlr6sC6Mr4riGgl8Rg09XHHnRZQw=
APP_ENV: testing
DB_CONNECTION: companyname-postgres
DB_DATABASE: db_test
DB_USERNAME: root
DB_PASSWORD: 1234
Because you are outside docker, so you should execute docker-compose exec companyname_app php artisan test, that will execute the tests INSIDE the docker container, where you correctly have everything setup.
So your code (if I am not missing anything) should be:
- name: Run test
run: docker-compose exec companyname_app php artisan test
env:
APP_KEY: base64:x06N/IsV5iJ+R6TKlr6sC6Mr4riGgl8Rg09XHHnRZQw=
APP_ENV: testing
DB_CONNECTION: companyname-postgres
DB_DATABASE: db_test
DB_USERNAME: root
DB_PASSWORD: 1234
But I am not certaing what will you get back from that execution, I have no idea if the test fails, if the CI/CD (I am assuming you are using GitHub Actions or Bitbucket Pipelines), will truly identify that it has failed or not.
What I usually do, is just install everything on the machine (CI/CD machine), instead of using a docker file or docker-compose yaml. But that is my preference (at least for PHP/Laravel)

How to expose vite js host to the outside docker

I'm new in vite js when upgrade from Laravel version 8 to 9.
I'm building docker for a Laravel 9 project use vite js. There is a problem: I can't expose host of resources out of docker containers. It's still working in the inside docker containers.
Are there any advice ? Thanks.
This is my docker-compose file
version: "3.9"
services:
nginx:
image: nginx:1.23-alpine
ports:
- 80:80
mem_limit: "512M"
volumes:
- type: bind
source: ./api
target: /usr/share/nginx/html/api
- type: bind
source: ./docker/nginx/dev/default.conf
target: /etc/nginx/conf.d/default.conf
php:
platform: linux/amd64
build:
context: .
dockerfile: ./docker/php/dev/Dockerfile
mem_limit: "512M"
volumes:
- type: bind
source: ./api
target: /usr/share/nginx/html/api
oracle:
platform: linux/amd64
image: container-registry.oracle.com/database/express:21.3.0-xe
ports:
- 1521:1521
# - 5500:5500
volumes:
- type: volume
source: oracle
target: /opt/oracle/oradata
volumes:
oracle:
I figured out issue. Caused vite does not expose host to network.
My solution is:
edit file package.json
"scripts": {
"dev": "vite --host",
"build": "vite build"
}
expose 5173 port in docker-compose.yml file
php:
platform: linux/amd64
build:
context: .
dockerfile: ./docker/php/dev/Dockerfile
mem_limit: "512M"
ports:
- 5173:5173
volumes:
- type: bind
source: ./api
target: /usr/share/nginx/html/api
There has been voiced downsides to named volumes #David Maze.
Since you can't access the contents of a named volume from outside of Docker, they're harder to back up and manage, and a poor match for tasks like injecting config files and reviewing logs.
Would you try altering all volume types to bind.
Mount volume from host in Dockerfile long format

How to run bash scripts via NPM in Docker container

I am unable to properly run bash scripts with NPM within a Docker container. If NPM is used to run a bash script then it runs it as a nameless user with ID 1000 that cannot use sudo to change file permissions and cannot call further NPM scripts.
Dockerfile:
FROM php:8.1-apache
RUN a2enmod rewrite
RUN docker-php-ext-install mysqli
RUN apt-get -y update && apt-get install -y zip mariadb-client git sudo
RUN adduser root sudo
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
RUN . ~/.bashrc && nvm install node
WORKDIR /var/www/html
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
docker-compose.yml
networks:
foundation:
services:
server:
build:
context: .
dockerfile: ./docker/server/Dockerfile
container_name: '${APP_NAME}-server'
ports:
- '${APP_PORT}:80'
working_dir: /var/www/html
environment:
- 'DATABASE_URL=mysql://${MYSQL_USER}:${MYSQL_PASSWORD}#db_server:3306/${MYSQL_DATABASE}?serverVersion=10.7'
volumes:
- ./code:/var/www/html
- ./docker/server/apache/sites-enabled:/etc/apache2/sites-enabled
- ./docker/server/php/php.ini:/usr/local/etc/php/conf.d/extra-php-config.ini
depends_on:
db_server:
condition: service_healthy
networks:
- foundation
db_server:
image: mariadb:10.7
container_name: '${APP_NAME}-db'
restart: always
ports:
- '${DB_PORT}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${MYSQL_PASSWORD}'
MYSQL_USER: '${MYSQL_USER}'
MYSQL_PASSWORD: '${MYSQL_PASSWORD}'
MYSQL_DATABASE: '${MYSQL_DATABASE}'
volumes:
- db_data:/var/lib/mysql
- ./docker/db/mariadb/my.cnf:/etc/mysql/conf.d/my.cnf
healthcheck:
test: mysqladmin ping -h 127.0.0.1 -u root --password=$$MYSQL_PASSWORD
interval: 5s
retries: 5
networks:
- foundation
volumes:
db_data:
package.json
{
"name": "#foundation/foundation",
"version": "1.0.0",
"description": "Foundation PHP web app",
"license": "UNLICENSED",
"private": true,
"scripts": {
"install-app": "bash ./install.sh",
"prod": "webpack --mode=production"
},
"dependencies": {
"preact": "^10.5.15"
},
"devDependencies": {
"#babel/core": "^7.15.8",
"#babel/plugin-transform-react-jsx": "^7.14.9",
"autoprefixer": "^10.3.7",
"babel-loader": "^8.2.3",
"css-loader": "^6.4.0",
"css-minimizer-webpack-plugin": "^3.1.1",
"mini-css-extract-plugin": "^2.4.3",
"postcss-loader": "^6.2.0",
"tailwindcss": "^2.2.17",
"webpack": "^5.59.1",
"webpack-cli": "^4.9.1"
}
}
install.sh
#!/bin/bash
set -e
read -p 'Enter Apache user:group [www-data:www-data]: ' usergroup
usergroup=${usergroup:-www-data:www-data}
sudo chmod 774 storage && sudo chown $usergroup storage
sudo chmod 774 tmp && sudo chown $usergroup tmp
touch log/errors.log && sudo chmod 664 log/errors.log && sudo chown $usergroup log/errors.log
touch log/exceptions.log && sudo chmod 664 log/exceptions.log && sudo chown $usergroup log/exceptions.log
npm i && npm run prod
root#0021ca12a934:/var/www/html# npm run install-app
> #foundation/foundation#1.0.0 install-app
> bash ./install.sh
Enter Apache user:group [www-data:www-data]:
sudo: you do not exist in the passwd database
sudo: you do not exist in the passwd database
sudo: you do not exist in the passwd database
sudo: you do not exist in the passwd database
./install.sh: line 9: npm: command not found
And if I try to call the install script directly:
root#0021ca12a934:/var/www/html# bash ./install.sh
Enter Apache user:group [www-data:www-data]:
up to date, audited 373 packages in 1s
53 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
> #foundation/foundation#1.0.0 prod
> webpack --mode=production
/usr/bin/env: 'node': Permission denied

Docker compose working_dir issue

I am trying to run a golang app using docker-compose, below is my compose configuration.
version: '2'
services:
#Application container
go:
image: golang:1.8-alpine
ports:
- "80:8080"
links:
- mongodb
environment:
DEBUG: 'true'
PORT: '8080'
working_dir: /go/src/simple-golang-app
command: go run main.go
volumes:
- ./simple-golang-app:/go/src/simple-golang-app
mongodb:
image: mvertes/alpine-mongo:3.2.3
restart: unless-stopped
ports:
- "27017:27017"
On running the compose using command "docker-compose up" i get error "stat main.go: no such file or directory" even when main.go is available in working directory.
it works fine when your host dir layout is
oxo#thor ~/Dropbox/Documents/code/docker/golang_working_dir $ find .
.
./docker-compose.yaml
./simple-golang-app
./simple-golang-app/main.go
so here we
cd ~/Dropbox/Documents/code/docker/golang_working_dir
docker-compose up
for a more complex build involving dependancies I use a Dockerfile :
FROM golang:1.8-alpine
RUN mkdir -p /go/src/simple-golang-app/
COPY simple-golang-app/main.go /go/src/simple-golang-app
WORKDIR /go/src/simple-golang-app
RUN apk add --no-cache git mercurial && go get -v -t ./... && apk del git mercurial
RUN go install ./...
RUN go build
ENV PORT 9000
now update your docker-compose.yaml to use this new image :
old
image: golang:1.8-alpine
new
image: nirmal_golang_alpine:latest
so your commands are
docker build --tag nirmal_golang_alpine
docker-compose up

How to use a separate node container in your ddev setup?

Sometimes you want to use a custom node version in your ddev setup. I will give an example configuration how this can be archived.
Create a file in .ddev folder named docker-compose.node.yaml with the following content:
version: '3.6'
services:
node:
container_name: ddev-${DDEV_SITENAME}-node
image: node:10.6
user: "node"
restart: "no"
labels:
com.ddev.site-name: ${DDEV_SITENAME}
com.ddev.platform: ddev
com.ddev.app-type: php
com.ddev.approot: $DDEV_APPROOT
volumes:
- "../:/var/www/html:cached"
working_dir: /var/www/html
command: ["tail", "-f", "/dev/null"]
Ddev will start a separate node container that is not terminated after startup.
You can ssh into that container using the command ddev ssh -s node
You can also configure post-start hook like this:
hooks:
post-start:
- exec-host: ddev exec -s node npm ci --quiet
- exec-host: ddev exec -s node npm start

Resources