作者: javacomhk 時間: 2022-5-13 01:46 標題: 如何使用Linux/ChromeOS開發Google Apps Script WebApp唔使自己起Server
本帖最後由 javacomhk 於 2022-5-20 04:32 編輯
Google Apps Script WebApp 開發使用 React.js + React-Bootstrap + Google Apps Script 教學
使用Google Apps Script WebApp 嘅好處係個 WebApp 嘅 Frontend 同 Backend 都可以完全放響個 cloud 度,的 data 就放響 Google Spreadsheet 度。個 WebApp 同時可以透過 Google Apps Script 使用 Google 的其他 backend 服務,包括 Gmail, Google Form, Calendar及其他另外要付費的 API 例如 Map Data。
Frontend 的製作部份可以選擇 JavaScript 的 framework 或 Library ,這樣 frontend 及 backend Language 都會有一致性的是用 JavaScript 。JavaScript Framework 可以係 React.js 然後用 Parcel.js 製作(generate) 成一個 Single Page App 嘅 index.html 接著部署(Deploy) 去做 Google Apps Script WebApp,而唔使手動在 Browser 打 html text。較早之前 Google 普通用戶是可以 deploy Anonymous Anyone 嘅 WebApp 而且係免費嘅,但係最近就改咗要 Google Workspace 戶口(同時以前嘅叫 GSuite 戶口亦沒咗免費用戶) 變相要付費用戶先可以比 Anyone Anonymous Access WebApp。但係開發比自己測試使用仍然免費。如果 Single Page WebApp 開發成功,加上有 Domain Email,其實個 Business Plan 商業戶口嘅月費都算合理。
如果是以前 GSuite 舊 Free Plan 用戶,現在轉 Google Workspace 仲有試用特價如下:
[attach]2320105[/attach]
Google 剛提出的 私人用途免費方案(5月18),讓用戶可以繼續使用自訂網域存取 Gmail 以及其他 Google Workspace 服務。
唯一嘅問題係 Google Server 嘅野,大陸係用唔到,只係香港及外國用到。不過反過來諗,可能又係優點。
Development Machine 我就介紹用 ChromeOS (不過 Linux 或 Windows WSL2 [要更新nodejs版本] 都可以),另外唔使一定要買 Chromebook 先有 ChromeOS 嘅,可以用部 Windows 機裝隻 USB Bootable 手指ChromeOS 都用得。用 ChromeOS 嘅好處係佢有 Linux 及有 Google Play Store。除了可以裝唔同嘅 Desktop Browser 去試個 WebApp 之外,亦可以透過 Google Play Store 裝不同的 Mobile Browser (例如 Chrome, Firefox, Edge等) 去試個 WebApp。當然 Safari 就無計要用 iOS 或 macOS 去試。另外如果使用 React.js framework 去做 localhost 測試個 Chrome Desktop Browser 係可以裝個 Chrome WebStore 嘅 React Developer Tools 去 Debug WebApp 嘅 React.js components。
開發呢個 WebApp 概覽流程包括如下:
(1) 在 Linux 安裝 需要嘅 package 及 需要的 JavaScript Framework 或 Library
包括 nodejs, npm, react.js, parcel.js, clasp及 react-bootstrap。見下文二樓詳細安裝步驟。
react.js + bootstrap 讓你可以很快地用 JavaScript 開發 WebApp 的 UI 控制或事件及使用 bootstrap 出名嘅 CSS library components。
(2) 寫及改 code 可在 local machine,並可以選擇使用最受歡迎的 Visual Studio Code 或其他自己喜歡的 Editor。如果是使用 Windows 版嘅 Visual Studio Code 要打開 WSL2 嘅 filesystem 嘅路徑係例如要輸入 \\wsl$\home\username\webappreact
由於要使用 parcel.js 去 build Single Page App(SPA) 嘅 index.html 所以個 React.js Project file structure 會有別於其他 React.js 項目。見下文二樓詳細 project 檔案 setup 嘅步驟。
(3) 寫好 code 後就可以先在 localhost 測試 front end interface ,相關嘅 Terminal 指令係
- npm run build
- npm run start
(4) 用 parcel.js 製作(generate) 成 Single Page App 後將個 index.html 及相關 Google Apps Script 用 clasp 推送(push) 去 Google Drive
在第一次使用 clasp push 去 Google Drive 是需要在local machine Login 和做 authentication 及後要去你的 Google Account enable Google App Script API 後才用 clasp 指令去 create project,此項目相關嘅Terminal 指令係
- npm run glogin
- # Browser will then startup for authorization
- npm run gcreate
- # create a spreadsheet project for storage of data and Apps Script
- npm run build
- npm run gpush
用 Browser 去 drive.google.com 選擇 Recent 找到 React Test App 的 Spreahsheet 打開佢,開啟 menu 的 Extensions 下的 Apps Script 然選擇 Deploy 後在 Test developments 找到 Web app URL的地址用 Browser 進入測試。
(6) 在 Google App Script Editor 內開發及測試其他輔助 Google 的服務例如 Google Form (例如 Quiz 或問卷)或 Gmail (例如 Mail-merge) 相關的功能。 最後購買 Google Workspace 就可以 部署(Deploy) 個 WebApp to Production。
(7) 在開發的過程中當然要用 git 去 keep 版本及歷史啦。
作者: javacomhk 時間: 2022-5-13 01:46
本帖最後由 javacomhk 於 2022-5-19 10:53 編輯
(A) 第一部份新增項目 folder,安裝 Framework、Library 及建立初始項目檔案
如果是 Windows WSL2 用戶就要例如 Ubuntu 內安裝完 nodejs 後更新 nodejs version 去最少 V12
參考 https://docs.microsoft.com/en-us ... cript/nodejs-on-wsl
(A1) 打開 Linux Terminal輸入以下指令
- sudo apt update
- sudo apt install nodejs npm wget git
- mkdir -p ~/webappreact
- cd ~/webappreact
- npm init -y
- {
- "name": "webappreact",
- "version": "1.0.0",
- "description": "",
- "scripts": {
- "glogin": "clasp login",
- "glogout": "clasp logout",
- "gcreate": "clasp create --title 'React Test Project' --rootDir ./apps-script",
- "gpush": "clasp push",
- "gpull": "clasp pull",
- "gstart": "clasp push --watch",
- "build": "parcel build src/index.html --dist-dir ./apps-script",
- "start": "parcel src/index.html --dist-dir ./apps-script"
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- "optionalDependencies": []
- }
- # install dependencies
- npm install -D @google/clasp
- npm install -D @types/google-apps-script # if you use VS Code Editor in ChromeOS
- npm install -D parcel
- npm install react react-dom
- npm install react-router-dom@6
(A4) 打開 Linux Terminal 輸入以下指令新增以下 folders
- mkdir -p ~/webappreact/src
- mkdir -p ~/webappreact/src/styles
- mkdir -p ~/webappreact/src/components
- mkdir -p ~/webappreact/apps-script
由於這個 forum 唔比 post HTML code,所以唯有 post image。
如果用 VS Code Editor,你打 html:5 就會出現這段類似的 code snippet,修改下就可以用。
[attach]2319938[/attach]
(A6) 新增以下文件 ~/webappreact/src/index.js 內容為
- import React from "react"
- import { BrowserRouter } from "react-router-dom"
- import App from "./App"
- import { createRoot } from 'react-dom/client';
- const container = document.getElementById('app');
- const root = createRoot(container);
- root.render(<BrowserRouter><App /></BrowserRouter>)
- import { Routes, Route } from "react-router-dom"
- import Home from "./components/Home"
- import About from "./components/About"
- import Nav from "./components/Nav"
- function App() {
- return <>
- <Nav />
- <Routes>
- <Route path="/" element={<Home />} />
- <Route path="about" element={<About />} />
- <Route path="*" element={<Home />} />
- </Routes>
- </>
- }
- export default App
- .App {
- text-align: center;
- }
- .App-logo {
- height: 40vmin;
- pointer-events: none;
- }
- .App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
- }
- .App-link {
- color: #61dafb;
- }
- .h1 {
- color:green;
- font-size: 2rem;
- }
- .css-nav {
- padding: 15px;
- }
- function Home() {
- return <>
- <h1 className="h1">HomePage</h1>
- </>
- }
- export default Home
- function About() {
- return <>
- <h1 className="h1">About</h1>
- </>
- }
- export default About
- import { Link } from "react-router-dom"
- function Nav() {
- return <>
- <span className="css-nav"><Link to="/">Home</Link></span>
- <span className="css-nav"><Link to="/about">About</Link></span>
- </>
- }
- export default Nav
- # Test building
- cd ~/webappreact
- #如果只在 localhost 做測試UI 可以唔使 build 只要儲存修改好的檔案便可
- #npm run build
- # Test running in localhost:1234
- npm run start
Debug 的方法是 Right Click 個網頁選擇 Inspect Element 後就可以選擇 Elements 或 Console 去睇 Elements 內的 html tag/style 或 JavaScript code 或者 Console/Error Logs 或使用 React Developer Tools 新增的 Components 及 Profiler Tab 。React Developer Tools 的使用可參考 https://www.digitalocean.com/com ... act-developer-tools
(B) 第二部份修改 code 內容及 推送(push) 到 Google Apps Script 部署(Deploy) 為 WebApp,及測試比較
(B1) 修改以下文件 ~/webappreact/src/App.js 內容為
- import { Routes, Route } from "react-router-dom"
- import Home from "./components/Home"
- import About from "./components/About"
- import Data from "./components/Data"
- import Nav from "./components/Nav"
- function App() {
- return <>
- <Nav />
- <Routes>
- <Route path="/" element={<Home />} />
- <Route path="/about" element={<About />} />
- <Route path="/data" element={<Data />} />
- <Route path="*" element={<Home />} />
- </Routes>
- </>
- }
- export default App
- import { Link } from "react-router-dom"
- function Nav() {
- return <>
- <span className="css-nav"><Link to="/">Home</Link></span>
- <span className="css-nav"><Link to="about">About</Link></span>
- <span className="css-nav"><Link to="data">Data</Link></span>
- </>
- }
- export default Nav
- import React, {useState, useEffect} from "react"
- function Data() {
- const [data,setData] = useState(null)
- const [loading, setLoading] = useState(false)
- if (typeof google === 'object') {
- useEffect(()=>{
- setLoading(true)
- google.script.run.withSuccessHandler(response => {
- setData([...response])
- setLoading(false)
- //console.log(JSON.stringify(data))
- }).withFailureHandler(er => {
- alert(er)
- }).getData()
- },[])
- }
- else {
- return <>
- <h1 className="h1">Test getData from local host</h1>
- <table>
- <tbody>
- <tr>
- <td><span style={{padding:'30px'}}>key: row.key</span></td>
- <td><span style={{padding:'30px'}}>value: row.value</span></td>
- </tr>
- </tbody>
- </table>
- </>
- }
- if (loading) return <h1>loading...</h1>
- if (!data) return null;
- console.log(JSON.stringify(data))
- return <>
- <h1 className="h1">Test getData from Google Web App</h1>
- <table>
- <tbody>
- {
- data.map((row) => (
- <tr>
- <td><span style={{padding:'30px'}}>key: {row.key}</span></td>
- <td><span style={{padding:'30px'}}>value: {row.value}</span></td>
- </tr>
- ))
- }
- </tbody>
- </table>
- </>
- }
- export default Data
- function doGet() {
- return HtmlService.createTemplateFromFile("index")
- .evaluate()
- .addMetaTag("viewport","width=device-width, initial-scale=1.0")
- }
- function getData() {
- return (
- [{
- "key": "apple",
- "value": "green"
- },
- {
- "key": "banana",
- "value": "yellow"
- }]
- );
- }
- function getSpreadData() {
- return SpreadsheetApp
- .getActiveSpreadsheet()
- .getActiveSheet()
- .getDataRange()
- .getValues();
- }
[attach]2319971[/attach]
(B6) 然後需要在 Project folder Login 及取得 Authentication token 及 create project, 打開 Linux Terminal 輸入以下指令
- cd ~/webappreact
- # Login in to google apps script
- npm run glogin
- # Login 後就會將個 Authentication toke 儲在 project folder 下
- # Create Project in google apps script and choose sheets
- npm run gcreate
- # 選擇 sheets 後就會在你的 Google Drive 內新增一個 Google Sheets 檔案叫 React Test Project,內里就會有你的 WebApp Code, Apps Script Code 及 Spreadsheets data
- # Move the .clasp.json to proper place before push
- mv ~/webappreact/apps-script/.clasp.json ~/webappreact/
- # Build and Push the SPA (index.html) and the Apps Script to React Test Project
- npm run build
- npm run gpush
選擇 Recent 找到 React Test App 的 Spreahsheet 檔案 Double Click 打開佢,開啟 menu 的 Extensions 下的 Apps Script 就可進入 Google Apps Script Editor,然後選擇右上角藍色的 Deploy Button 後選擇 New Deployment,Select type 內選擇 Web app再 Click Done Button。然後再選擇右上角藍色的 Deploy Button 後選擇 Test developments 找到 Web app URL的地址 Copy 後用 Browser 進入測試。
[attach]2319982[/attach]
(B8) 每次修改完 Code 後要在 localhost 測試,可以打開 Linux Terminal 輸入以下指令然後用 Browser 去 http://localhost:1234 測試
- cd ~/webappreact
- #如果只在 localhost 做測試UI 可以唔使 build 只要儲存修改好的檔案便可
- #npm run build
- npm run start
- cd ~/webappreact
- npm run build
- npm run gpush
[attach]2319996[/attach]
作者: javacomhk 時間: 2022-5-13 01:47
本帖最後由 javacomhk 於 2022-5-23 22:21 編輯
(C) 第三部份安裝 Bootstrap,及修改 code 內容,再用 Desktop Browser 及 Mobile Browser 測試
經過兩個部分新增的Code 你會發現 React.js 是會用一種進化了的 JavaScript 語言叫 JSX 去建立 UI的控制。詳細 JSX 的使用請參考 https://reactjs.org/docs/introducing-jsx.html
但網頁是最少要有圖片及配合相關文字的不同格式及連結才有現代網頁嘅感覺,Bootstrap 就提供了非常豐富及不同種類的 CSS library 安裝後就可即時使用並且可在各種 mobile browser 都能自適應及使用到,詳細 React-Bootstrap 使用例子可參考 https://react-bootstrap.netlify.app/
在使用 Google Apps Script WebApp 有2點限制要特別留意及明白,所有圖片必需是網上資源的 Url 地址(見下面C3的url Background1 例子)或者如是 local image file 是經轉換後的 inline style 的 hex64 string 圖片(見下面C2及C3的 data-url 例子)。所有 CSS 文檔要是網上資源的 Url 地址,或者是已 import 在 src/index.html 內(見下面 C4的 import 例子)。即是話經 parcel.js build 出來的 Code 及任何 Assets 都應該全部在及只可以有一個 index.html 檔案(真正實現 Single Page WebApp),其他類型的檔案都不會被推送(push) 上 Google Apps Script 及被 Google WebApp 使用到。
(C1) 安裝 Bootstrap,打開 Linux Terminal輸入以下指令
- cd ~/webappreact
- npm install react-bootstrap bootstrap --force
- import React from "react"
- import { Container, Card, Button } from 'react-bootstrap'
- import img1 from 'data-url:../img/01-200x300.jpg'
- function About() {
- return <>
- <div className="App">
- <header className="App-header">
- <Container>
- <Card className="mb3" style={{ color: "#000" }}>
- <Card.Img src={img1} />
- <Card.Body>
- <Card. Title>
- Card Example
- </Card.Title>
- <Card.Text>
- This is an example of react bootstrap card
- </Card.Text>
- <Button variant="primary">Read More</Button>
- </Card.Body>
- </Card>
- </Container>
- </header>
- </div>
- </>
- }
- export default About
- import React from "react"
- import { Container, Row, Col, Breadcrumb, Card, Button } from 'react-bootstrap'
- import { Link } from "react-router-dom"
- const Background1 = "https://picsum.photos/800/300"
- import img2 from 'data-url:../img/02-800x300.jpg'
- function Home() {
- return <>
- <div className="App">
- <header className="App-header">
- <Row>
- <Breadcrumb>
- <Breadcrumb.Item active href="#">Home</Breadcrumb.Item>
- <Breadcrumb.Item href="https://getbootstrap.com/docs/4.0/components/breadcrumb/">
- Library
- </Breadcrumb.Item>
- <Breadcrumb.Item><Link to="data">Data</Link></Breadcrumb.Item>
- </Breadcrumb>
- </Row>
- <Row>
- <Col>
- <div>
- <Card className="mb3" style={{backgroundImage : `url(${Background1})`}}>
- <Card.Header>Featured</Card.Header>
- <Card.Body>
- <Card.Title>Special title treatment</Card.Title>
- <Card.Text className="overlay-content has-bg-img rounded">
- With supporting text below as a natural lead-in to additional content.
- </Card.Text>
- <Button variant="primary">Go somewhere</Button>
- </Card.Body>
- </Card>
- </div>
- </Col>
- <Col>
- <div>
- <Card className="mb-3 text-muted" style={{backgroundImage : `url(${img2})`}}>
- <Card.Body>
- <Card.Title>Card Title</Card.Title>
- <Card.Subtitle className="text-muted">Card Subtitle</Card.Subtitle>
- <Card.Text>
- Some quick example text to build on the card title and make up the bulk of
- the card's content.
- </Card.Text>
- <Card.Link href="#">Card Link</Card.Link>
- <Card.Link href="#">Another Link</Card.Link>
- </Card.Body>
- </Card>
- </div>
- </Col>
- </Row>
- </header>
- </div>
- </>
- }
- export default Home
- <style>
- @import "./styles/main.scss";
- @import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
- </style>
[attach]2319998[/attach]
(C5) 下載一些隨機 sample 圖片並保存在項目文件夾下的 src/img 文件夾中作網頁測試用途,打開 Linux Terminal 輸入以下指令
- mkdir -p ~/webappreact/src/img
- wget https://picsum.photos/200/300 -O ~/webappreact/src/img/01-200x300.jpg
- wget https://picsum.photos/800/300 -O ~/webappreact/src/img/02-800x300.jpg
[attach]2320003[/attach]
作者: javacomhk 時間: 2022-5-13 04:31
本帖最後由 javacomhk 於 2022-7-3 05:12 編輯
(D) 第四部份講解個 WebApp Input Form Data 使用 Google Spreadsheet
續篇 https://www.hkepc.com/forum/viewthread.php?fid=24&tid=2663029
(E) 第五部份 WebApp Backend webscrape 功能
Webscrape backend 功能 https://www.hkepc.com/forum/viewthread.php?fid=24&tid=2663555
(F) 第六部份 API Content Service 功能 serving JSON
API serving JSON 功能 https://www.hkepc.com/forum/viewthread.php?fid=24&tid=2663555
