# syntax = docker/dockerfile:1
FROM node:slim as build
RUN apt-get update &&\
apt-get install -y autoconf bison patch build-essential \
libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libgmp-dev \
libncurses5-dev libffi-dev libgdbm6 libgdbm-dev libdb-dev uuid-dev \
git curl &&\
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y &&\
export PATH=/root/.cargo/bin:$PATH &&\
git clone https://github.com/rbenv/ruby-build.git /opt/ruby-build &&\
/opt/ruby-build/install.sh &&\
ruby-build 3.2.0 /usr/local
RUN gem install rails
RUN rails new demo --skip-active-record --javascript esbuild
WORKDIR demo
RUN yarn add react react-dom
FROM node:slim
WORKDIR demo
COPY --from=build /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
COPY --from=build /usr/local /usr/local
COPY --from=build /demo /demo
RUN bin/rails generate controller Time index
RUN cat <<-"EOF" >> app/javascript/application.js
import "./components/counter"
EOF
RUN mkdir app/javascript/components
COPY <<-"EOF" app/javascript/components/counter.jsx
import React, { useState, useEffect, useRef } from 'react';
import { createRoot } from 'react-dom/client';
const Counter = ({ arg }) => {
const [count, setCount] = useState(0);
const countRef = useRef(count);
countRef.current = count;
useEffect(() => {
const interval = setInterval(() => {
setCount(countRef.current + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <div>{`${arg} - counter = ${count}!`}</div>;
};
document.addEventListener("DOMContentLoaded", () => {
const container = document.getElementById("root");
const root = createRoot(container);
root.render(<Counter arg={`
Node ${container.getAttribute('node')}
Ruby ${container.getAttribute('ruby')}
Rails ${container.getAttribute('rails')}`} />);
});
EOF
COPY <<-"EOF" app/views/time/index.html.erb
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin: 0;
}
svg {
height: 40vmin;
pointer-events: none;
margin-bottom: 1em;
}
@media (prefers-reduced-motion: no-preference) {
svg {
animation: App-logo-spin infinite 20s linear;
}
}
main {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<main>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-11.5 -10.23174 23 20.46348">
<title>React Logo</title>
<circle cx="0" cy="0" r="2.05" fill="#61dafb"/>
<g stroke="#61dafb" stroke-width="1" fill="none">
<ellipse rx="11" ry="4.2"/>
<ellipse rx="11" ry="4.2" transform="rotate(60)"/>
<ellipse rx="11" ry="4.2" transform="rotate(120)"/>
</g>
</svg>
<div id="root"
node=<%= `node -v`.strip.sub(/^v/, '') %>
ruby=<%= RUBY_VERSION %>
rails=<%= Rails::VERSION::STRING %>>
</div>
</main>
</body>
</html>
EOF
COPY <<-"EOF" config/routes.rb
Rails.application.routes.draw { root "time#index" }
EOF
ENV RAILS_ENV=production
RUN bin/rails assets:precompile
EXPOSE 3000
CMD bin/rails server