[教學] 如何使用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 仲有試用特價如下:


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 指令係
  1. npm run build
  2. npm run start
複製代碼
然後用Chrome Browser (安裝好 React Developer Tools 後) 去 localhost:1234 做測試及 Debug

(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 指令係
  1. npm run glogin
  2. # Browser will then startup for authorization
  3. npm run gcreate
  4. # create a spreadsheet project for storage of data and Apps Script
複製代碼
新增項目完成後就可以將 build 好的 optimized code 用 clasp push 去Google Apps Script,相關嘅Terminal 指令係
  1. npm run build
  2. npm run gpush
複製代碼
(5) 在 Google Apps Script 部署(Deploy) 好 WebApp 後再用 Browser 去測試 frontend 及 backend 的 code。
用 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-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輸入以下指令
  1. sudo apt update
  2. sudo apt install nodejs npm wget git
  3. mkdir -p ~/webappreact
  4. cd ~/webappreact
  5. npm init -y
複製代碼
(A2) 將以下文件 ~/webappreact/package.json 更改內容為
  1. {
  2.   "name": "webappreact",
  3.   "version": "1.0.0",
  4.   "description": "",
  5.   "scripts": {
  6.     "glogin": "clasp login",
  7.     "glogout": "clasp logout",
  8.     "gcreate": "clasp create --title 'React Test Project' --rootDir ./apps-script",
  9.     "gpush": "clasp push",
  10.     "gpull": "clasp pull",
  11.     "gstart": "clasp push --watch",
  12.     "build": "parcel build src/index.html --dist-dir ./apps-script",
  13.     "start": "parcel src/index.html --dist-dir ./apps-script"
  14.   },
  15.   "keywords": [],
  16.   "author": "",
  17.   "license": "ISC",
  18.   "optionalDependencies": []
  19. }
複製代碼
(A3) 打開 Linux Terminal 輸入以下指令安裝 JavaScript Framework
  1. # install dependencies  
  2. npm install -D @google/clasp
  3. npm install -D @types/google-apps-script # if you use VS Code Editor in ChromeOS
  4. npm install -D parcel
  5. npm install react react-dom
  6. npm install react-router-dom@6
複製代碼
如果使用 VS code Editor,就要安裝 @types/google-apps-script

(A4) 打開 Linux Terminal 輸入以下指令新增以下 folders
  1. mkdir -p ~/webappreact/src
  2. mkdir -p ~/webappreact/src/styles
  3. mkdir -p ~/webappreact/src/components
  4. mkdir -p ~/webappreact/apps-script
複製代碼
(A5) 新增以下文件  ~/webappreact/src/index.html 內容為
由於這個 forum 唔比 post HTML code,所以唯有 post image。
如果用 VS Code Editor,你打 html:5 就會出現這段類似的 code snippet,修改下就可以用。



(A6) 新增以下文件 ~/webappreact/src/index.js 內容為
  1. import React from "react"
  2. import { BrowserRouter } from "react-router-dom"
  3. import App from "./App"
  4. import { createRoot } from 'react-dom/client';
  5. const container = document.getElementById('app');
  6. const root = createRoot(container);
  7. root.render(<BrowserRouter><App /></BrowserRouter>)
複製代碼
(A7) 新增以下文件 ~/webappreact/src/App.js 內容為
  1. import { Routes, Route } from "react-router-dom"
  2. import Home from "./components/Home"
  3. import About from "./components/About"
  4. import Nav from "./components/Nav"

  5. function App() {
  6.   return <>
  7.       <Nav />
  8.       <Routes>
  9.         <Route path="/" element={<Home />} />
  10.         <Route path="about" element={<About />} />
  11.         <Route path="*" element={<Home />} />
  12.       </Routes>
  13.     </>
  14. }
  15. export default App
複製代碼
(A8) 新增以下文件 ~/webappreact/src/styles/main.scss 內容為
  1. .App {
  2.   text-align: center;
  3. }

  4. .App-logo {
  5.   height: 40vmin;
  6.   pointer-events: none;
  7. }

  8. .App-header {
  9.   background-color: #282c34;
  10.   min-height: 100vh;
  11.   display: flex;
  12.   flex-direction: column;
  13.   align-items: center;
  14.   justify-content: center;
  15.   font-size: calc(10px + 2vmin);
  16.   color: white;
  17. }

  18. .App-link {
  19.   color: #61dafb;
  20. }

  21. .h1 {
  22.   color:green;
  23.   font-size: 2rem;
  24. }

  25. .css-nav {
  26.   padding: 15px;
  27. }
複製代碼
(A9) 新增以下文件 ~/webappreact/src/components/Home.js 內容為
  1. function Home() {
  2.   return <>
  3.     <h1 className="h1">HomePage</h1>
  4.   </>
  5. }
  6. export default Home
複製代碼
(A10) 新增以下文件 ~/webappreact/src/components/About.js 內容為
  1. function About() {
  2.   return <>
  3.     <h1 className="h1">About</h1>
  4.   </>
  5. }
  6. export default About
複製代碼
(A11) 新增以下文件 ~/webappreact/src/components/Nav.js 內容為
  1. import { Link } from "react-router-dom"

  2. function Nav() {
  3.   return <>
  4.         <span className="css-nav"><Link to="/">Home</Link></span>
  5.         <span className="css-nav"><Link to="/about">About</Link></span>
  6.   </>
  7. }
  8. export default Nav
複製代碼
(A12) 打開 Linux Terminal 輸入以下指令進行第一次本地 localhost:1234 Browser 測試
  1. # Test building
  2. cd ~/webappreact
  3. #如果只在 localhost 做測試UI 可以唔使 build 只要儲存修改好的檔案便可
  4. #npm run build
  5. # Test running in localhost:1234
  6. npm run start
複製代碼
(A13) Linux 用戶可以在 Firefox 內安裝 React Developer Tools 進行測試及Debug。或加安裝 Google Chrome Browser 及 Chrome Web Store 內 React Developer Tools 去進行測試及Debug。

Debug 的方法是 Right Click 個網頁選擇 Inspect Element 後就可以選擇 ElementsConsole 去睇 Elements 內的 html tag/style 或 JavaScript code 或者 Console/Error Logs 或使用 React Developer Tools 新增的 ComponentsProfiler 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 內容為
  1. import { Routes, Route } from "react-router-dom"
  2. import Home from "./components/Home"
  3. import About from "./components/About"
  4. import Data from "./components/Data"
  5. import Nav from "./components/Nav"

  6. function App() {
  7.   return <>
  8.       <Nav />
  9.       <Routes>
  10.         <Route path="/" element={<Home />} />
  11.         <Route path="/about" element={<About />} />
  12.         <Route path="/data" element={<Data />} />
  13.         <Route path="*" element={<Home />} />
  14.       </Routes>
  15.     </>
  16. }
  17. export default App
複製代碼
(B2)  修改以下文件 ~/webappreact/components/Nav.js 內容為
  1. import { Link } from "react-router-dom"
  2. function Nav() {
  3.   return <>
  4.         <span className="css-nav"><Link to="/">Home</Link></span>
  5.         <span className="css-nav"><Link to="about">About</Link></span>
  6.         <span className="css-nav"><Link to="data">Data</Link></span>
  7.   </>
  8. }
  9. export default Nav
複製代碼
(B3) 新增以下文件 ~/webappreact/src/components/Data.js 內容為
  1. import React, {useState, useEffect} from "react"
  2. function Data() {
  3.   const [data,setData] = useState(null)
  4.   const [loading, setLoading] = useState(false)
  5.   if (typeof google === 'object') {
  6.     useEffect(()=>{
  7.       setLoading(true)
  8.       google.script.run.withSuccessHandler(response => {
  9.         setData([...response])
  10.         setLoading(false)
  11.         //console.log(JSON.stringify(data))
  12.       }).withFailureHandler(er => {
  13.         alert(er)
  14.       }).getData()
  15.     },[])
  16.   }
  17.   else {
  18.     return <>
  19.       <h1 className="h1">Test getData from local host</h1>
  20.       <table>
  21.         <tbody>
  22.           <tr>
  23.             <td><span style={{padding:'30px'}}>key: row.key</span></td>
  24.             <td><span style={{padding:'30px'}}>value: row.value</span></td>
  25.           </tr>
  26.         </tbody>
  27.       </table>
  28.     </>
  29.   }
  30.   if (loading) return <h1>loading...</h1>
  31.   if (!data) return null;
  32.   console.log(JSON.stringify(data))
  33.   return <>
  34.     <h1 className="h1">Test getData from Google Web App</h1>
  35.     <table>
  36.       <tbody>
  37.        {
  38.           data.map((row) => (
  39.           <tr>
  40.             <td><span style={{padding:'30px'}}>key: {row.key}</span></td>
  41.             <td><span style={{padding:'30px'}}>value: {row.value}</span></td>
  42.           </tr>
  43.          ))
  44.        }
  45.       </tbody>
  46.     </table>
  47.   </>
  48. }
  49. export default Data
複製代碼
(B4) 新增以下文件 ~/webappreact/apps-script/main.js 內容為
  1. function doGet() {
  2.   return HtmlService.createTemplateFromFile("index")
  3.   .evaluate()
  4.   .addMetaTag("viewport","width=device-width, initial-scale=1.0")
  5. }

  6. function getData() {
  7.   return (
  8.     [{
  9.       "key": "apple",
  10.       "value": "green"
  11.      },
  12.      {   
  13.      "key": "banana",
  14.      "value": "yellow"
  15.      }]
  16.   );
  17. }

  18. function getSpreadData() {
  19.   return SpreadsheetApp
  20.       .getActiveSpreadsheet()
  21.       .getActiveSheet()
  22.       .getDataRange()
  23.       .getValues();
  24. }
複製代碼
(B5) 新增及修改完 Code 後就可以 準備推送(push) 個 build 好嘅 Single Page App (SPA) 去 Google Drive 度。在推送(push)之前,首先用 Browser Login Google Account 及去 https://script.google.com/home/usersettings 去開啟(enable) Google Apps Script API,如下圖:


(B6) 然後需要在 Project folder Login 及取得 Authentication token 及 create project, 打開 Linux Terminal 輸入以下指令
  1. cd ~/webappreact
  2. # Login in to google apps script
  3. npm run glogin
  4. # Login 後就會將個 Authentication toke 儲在 project folder 下
  5. # Create Project in google apps script and choose sheets
  6. npm run gcreate
  7. # 選擇 sheets 後就會在你的 Google Drive 內新增一個 Google Sheets 檔案叫 React Test Project,內里就會有你的 WebApp Code, Apps Script Code 及 Spreadsheets data
  8. # Move the .clasp.json to proper place before push
  9. mv ~/webappreact/apps-script/.clasp.json ~/webappreact/
  10. # Build and Push the SPA (index.html) and the Apps Script to React Test Project
  11. npm run build
  12. npm run gpush
複製代碼
(B7) 個WebApp 是需要 Deploy to WebApp 才可測試,首先用 Browser 去 drive.google.com
選擇 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 進入測試。



(B8) 每次修改完 Code 後要在 localhost 測試,可以打開 Linux Terminal 輸入以下指令然後用 Browser 去 http://localhost:1234 測試
  1. cd ~/webappreact

  2. #如果只在 localhost 做測試UI 可以唔使 build 只要儲存修改好的檔案便可
  3. #npm run build
  4. npm run start
複製代碼
(B9) 每次修改完 Code 後要在 Google WebApp 測試,就要重覆 build 及 gpush 如下,(B6) 的 Test Deployment 步驟,不需重覆。只要是Browser 是同一 Google Login 戶口便可以測試。
  1. cd ~/webappreact
  2. npm run build
  3. npm run gpush
複製代碼
(B10) 在 localhost (如左邊圖) 及在 Google WebApp  (如右邊圖) 測試的結果會不同, 在 localhost 會使用 testing data然後顯示出來,在 Google Server 的 WebApp 則會取用 Google Apps Script function 內的 backend server data。
附件: 您需要登錄才可以下載或查看附件。沒有帳號?註冊

TOP

本帖最後由 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輸入以下指令
  1. cd ~/webappreact
  2. npm install react-bootstrap bootstrap --force
複製代碼
(C2) 修改以下文件 ~/webappreact/src/components/About.js 內容為
  1. import React from "react"
  2. import { Container, Card, Button } from 'react-bootstrap'
  3. import img1 from 'data-url:../img/01-200x300.jpg'

  4. function About() {
  5.   return <>
  6.     <div className="App">
  7.         <header className="App-header">
  8.          <Container>
  9.           <Card className="mb3" style={{ color: "#000" }}>
  10.             <Card.Img src={img1} />
  11.             <Card.Body>
  12.               <Card. Title>
  13.                 Card Example
  14.               </Card.Title>
  15.               <Card.Text>
  16.                 This is an example of react bootstrap card
  17.               </Card.Text>
  18.               <Button variant="primary">Read More</Button>
  19.             </Card.Body>
  20.           </Card>
  21.          </Container>
  22.         </header>
  23.     </div>
  24.   </>
  25. }

  26. export default About
複製代碼
(C3) 修改以下文件 ~/webappreact/src/components/Home.js 內容為
  1. import React from "react"
  2. import { Container, Row, Col, Breadcrumb, Card, Button } from 'react-bootstrap'
  3. import { Link } from "react-router-dom"
  4. const Background1 = "https://picsum.photos/800/300"
  5. import img2 from 'data-url:../img/02-800x300.jpg'

  6. function Home() {
  7.   return <>
  8.     <div className="App">
  9.       <header className="App-header">
  10.         <Row>
  11.           <Breadcrumb>
  12.           <Breadcrumb.Item active href="#">Home</Breadcrumb.Item>
  13.           <Breadcrumb.Item href="https://getbootstrap.com/docs/4.0/components/breadcrumb/">
  14.             Library
  15.           </Breadcrumb.Item>
  16.           <Breadcrumb.Item><Link to="data">Data</Link></Breadcrumb.Item>
  17.           </Breadcrumb>
  18.         </Row>
  19.         <Row>
  20.           <Col>
  21.             <div>
  22.               <Card className="mb3" style={{backgroundImage : `url(${Background1})`}}>
  23.                 <Card.Header>Featured</Card.Header>
  24.                 <Card.Body>
  25.                 <Card.Title>Special title treatment</Card.Title>
  26.                 <Card.Text className="overlay-content has-bg-img rounded">
  27.                   With supporting text below as a natural lead-in to additional content.
  28.                 </Card.Text>
  29.                 <Button variant="primary">Go somewhere</Button>
  30.                 </Card.Body>
  31.               </Card>
  32.             </div>
  33.           </Col>
  34.           <Col>
  35.             <div>
  36.               <Card className="mb-3 text-muted" style={{backgroundImage : `url(${img2})`}}>
  37.                 <Card.Body>
  38.                 <Card.Title>Card Title</Card.Title>
  39.                 <Card.Subtitle className="text-muted">Card Subtitle</Card.Subtitle>
  40.                 <Card.Text>
  41.                   Some quick example text to build on the card title and make up the bulk of
  42.                   the card's content.
  43.                 </Card.Text>
  44.                 <Card.Link href="#">Card Link</Card.Link>
  45.                 <Card.Link href="#">Another Link</Card.Link>
  46.                 </Card.Body>
  47.               </Card>
  48.             </div>
  49.           </Col>
  50.           </Row>
  51.         </header>
  52.     </div>
  53.   </>
  54. }

  55. export default Home
複製代碼
(C4) 修改以下文件 ~/webappreact/src/index.html 添加以下 style tag 下 import css 的語句
  1. <style>
  2.    @import "./styles/main.scss";
  3.    @import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
  4. </style>
複製代碼
添加後的 index.html 代碼像如下這張圖片內容一樣


(C5) 下載一些隨機 sample 圖片並保存在項目文件夾下的 src/img 文件夾中作網頁測試用途,打開 Linux Terminal 輸入以下指令
  1. mkdir -p ~/webappreact/src/img
  2. wget https://picsum.photos/200/300 -O ~/webappreact/src/img/01-200x300.jpg
  3. wget https://picsum.photos/800/300 -O ~/webappreact/src/img/02-800x300.jpg
複製代碼
(C6) 在 npm build 和 npm gpush(推送)之後進行測試後帶圖片/文字/連結及 bootstrap CSS 的網頁顯示結果(左邊圖是 About,右邊圖是 HomePage) 如下圖:
附件: 您需要登錄才可以下載或查看附件。沒有帳號?註冊

TOP

本帖最後由 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

TOP