Logo Vincent
返回文章列表

一篇文章开发todolist

Web
一篇文章开发todolist

【前言】

本文实战开发一个todolist,

基于以下技术栈:

react:开发ui, https://reactjs.org/

webpack,构建前端项目, https://webpack.js.org/

localStorage,存储数据, https://developer.mozilla.org/zh-CN/docs/Web/API/Window/localStorage

lerna,管理代码项目, https://lerna.js.org/

pm2,生产环境部署nodejs服务, https://pm2.keymetrics.io/

【使用lerna创建项目】

本次实战涉及两个项目:

dishi-server,nodejs服务端项目,简单的部署和跳转到首页

dishi-web,todolist,前端ui部分的项目

以上两个项目使用lerna进行管理,

lerna相关的使用可以看这篇文章: 一篇文章学会lerna

lerna安装和初始化

-- 安装
npm i -g lerna

-- 初始化,在项目下
lerna init

lerna创建项目

通过lerna的create命令,创建两个项目dishi-server和dishi-web

lerna create dishi-web

按提示会自动在packages文件夹下创建好对应的项目

lerna使用independent模式

默认生成的lerna.json内容如下

{
  "packages": [
    "packages/*"
  ],
  "version": "0.0.0"
}

在这个模式下,packages下所有项目的版本统一管理,

这样不太方便,修改为每个项目版本单独管理,如下

{
  "packages": [
    "packages/*"
  ],
  "version": "independent"
}

package.json修改为private模式

由于dishi-web,dishi-server并不对外发布npm包,

所以修改package.json内的private为true,

否则每次lerna publish时会自动发布npm包,

{
    "name": "dishi-web",
    "private": true,
    "version": "0.0.0",
    "scripts": {},
    "dependencies": {}
}

lerna publish提交项目

修改完以上内容后,可以git add,git cz提交到本地,

然后使用lerna的publish能力提交项目,

会自动打tag,加push

lerna publish

选择完每个项目对应版本后,会自动提交

lerna添加常用命令

在根项目下的package.json中添加lerna的常用命令

clean:清理packages下每个项目的依赖

init:安装packages下每个项目的依赖,添加—hoist参数代表将所有项目的依赖提取到根项目下

    "scripts": {
        "clean": "lerna clean -y",
        "init": "lerna bootstrap --ignore-prepublish --hoist"
    },

以上代码见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-web%400.0.2

【开发后端项目】

本次实战中后端项目比较简单,只需要跳转一个html即可

这里使用一个简单的nodejs下web框架实现, https://qiao-z.vincentqiao.com/#/

qiao-z:安装

npm i qiao-z

qiao-z:controller

qiao-z会自动扫描本地以Controller.js结尾的文件,并注册路由,

注册一个get请求,/*代表所有请求都会命中这个路由

/**
 * index controller
 */
module.exports = function (app) {
  // index
  app.get("/*", function (req, res) {
    res.render("./views/index.html");
  });
};

qiao-z:启动

其中app.js代码如下

"use strict";

// port
const port = require("./server/config.json").port;

// app
const app = require("qiao-z")();

// listen
app.listen(port);

启动

node app.js

启动后即可本地访问 http://localhost:9011/ ,效果如下

使用pm2在生产环境部署服务

生产环境下不适合用node启动,需要使用pm2, https://pm2.keymetrics.io/

pm2的使用,可以看这篇文章的介绍:一篇文章学会pm2

安装pm2

npm i -g pm2

pm2运行服务

pm2 start app.js --name dishi

效果如下

nginx反向代理及acme申请https证书

在自己服务器上配置一个nginx反向代理,

以及使用acme.sh申请https证书,

acme.sh的使用,可以看这篇文章的介绍:centos随笔04:acme.sh申请https证书

以上代码见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-server%400.0.3

【搭建前端项目】

前端项目基于react搭建,

构建使用qiao-webpack, https://qiao-webpack.vincentqiao.com/#/

webpack的使用,可以看这篇文章:一篇文章学会Webpack5.x

qiao-webpack:安装

npm i -D qiao-webpack

qiao-webpack:推荐配置

webpack的配置比较多,这里推荐使用如下的配置和结构

|--dishi-web
    |--webpack
        |--common
            |--alias.js
            |--entry.js
        |--dev
            |--plugins.js
            |--server.js
        |--prod
            |--output.js
            |--plugins.js
        |--template
            |--mobile.html
            |--pc.html
        |--qiao-webpack.dev.js
        |--qiao-webpack.prod.js

alias.js是webpack中别名设置,方便在代码内引入其他资源和文件

"use strict";

// path
const path = require("path");

// alias
module.exports = {
  "@components": path.resolve(__dirname, "../../src/components"),
  "@styles": path.resolve(__dirname, "../../src/styles"),
  "@utils": path.resolve(__dirname, "../../src/utils"),
  "@views": path.resolve(__dirname, "../../src/views"),
};

entry.js是webpack的文件入口,

"use strict";

// entry
module.exports = {
  // dishi
  "dishi-index-pc": "@views/dishi/dishi-index-pc-view.jsx",
  "dishi-index-mobile": "@views/dishi/dishi-index-mobile-view.jsx",
};

plugins.js是webpack设置plugin相关的参数,

本文中涉及的,一个是css压缩相关,一个是html生成相关

css压缩相关的,对应mini-css-extract-plugin,在qiao-webpack中已经内置

    // css
    {
        type: 'css',
        filename: '[name].[contenthash:8].css',
        chunkFilename: '[id].[contenthash:8].css',
        ignoreOrder: true,
    },

html生成相关的,对应html-webpack-plugin,在qiao-webpack中已经内置

    {
        type: 'html',
        inject: 'body',
        title: 'dishi-index-pc',
        chunks: ['dishi-index-pc'],
        filename: 'dishi-index-pc.html',
        template: pcPath,
    },

dev下的server.js是webpack中devServer相关配置

"use strict";

// path
const path = require("path");

// static path
const distPath = path.resolve(__dirname, "../../static");

/**
 * dev server
 */
module.exports = {
  port: 5277,
  static: distPath,
};

prod下的output.js是webpack中output相关配置

这里会将html构建到dishi-server/views文件夹,将静态文件构建到dishi-server/static文件夹

"use strict";

// path
const path = require("path");

// static path
const distPath = path.resolve(__dirname, "../../../dishi-server/static");

// output
module.exports = {
  filename: "[name].[contenthash:8].js",
  path: distPath,
  clean: true,
};

template下是两个html模板

qiao-webpack:构建

添加两个脚本

"dev": "qwebpack dev ./webpack/qiao-webpack.dev.js",
"build": "qwebpack build ./webpack/qiao-webpack.prod.js",

这里执行build命令,效果如下

对应的html和静态文件生成到了dishi-server下

这样就可以在dishi-server内访问构建好的html和静态文件,

这样做的好处是,

前端项目dishi-web对应前端开发,调试可以使用webpack dev本地调试,

后端项目dishi-server对应后端开发,直接使用前端构建好后的html和静态文件

qiao-cos:安装

如上所述,目前已经可以直接将dishi-server部署服务器了,

但是这里建议不要直接将静态文件,也就是css,js等部署到应用服务器,避免应用服务器的带宽压力

建议将静态文件上传到文件服务器,例如腾讯云的cos,阿里云的oss等

这里使用腾讯云的cos,开发了一个工具:qiao-cos, https://code.insistime.com/#/qiao-cos-cli

npm i -D qiao-cos

qiao-cos:上传

在dishi-web项目中添加脚本

"upload": "qcos fo ./config.json ../dishi-server/static 21_dishi_ls/static"

执行upload命令,效果如下

将对应的html文件,即dishi-server也部署后,访问效果如下

以上代码见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-web%400.0.3

【开发前端项目】

最终效果

1.在input中输入内容,回车添加todo

2.input下展示目前的todolist

3.点击某一个todo,完成todo项并移除

数据结构

每一个todo的数据结构如下,其中key为时间戳

{
    key: 1665400441283,
    value: '读一本书'
}

todo列表的数据结构是数组,如下

[
  {
    key: 1665400441283,
    value: "读一本书",
  },
];

qiao.ls.js:保存数据

数据使用localStorage保存,

具体使用可以看这篇文章:一篇文章学会localStorage

这里使用qiao.ls.js进行操作, https://code.insistime.com/#/qiao.ls.js

由于直接按key,value保存,在localStorage中会比较分散,

这里聚集一下,保存到命名空间todos,最终效果如下

添加todo,删除todo,获取todos的代码如下

// qiao
import { ls, cache } from "qiao.ls.js";

/**
 * add todo
 * @param {*} todo
 */
export const addTodo = (key, todo) => {
  cache("todos", key, todo);
};

/**
 * del todo
 * @param {*} key
 */
export const delTodo = (key) => {
  cache("todos", key, null);
};

/**
 * get todos
 * @returns
 */
export const getTodos = () => {
  // check
  const todos = ls("todos");
  if (!todos) return [];

  // res
  const res = [];
  for (const [key, value] of Object.entries(todos)) {
    res.push({
      key: key,
      value: value,
    });
  }

  return res;
};

实现todo input

1.在回车的时候进行保存

2.首先清空input

3.添加todo到localStorage内

4.刷新todo列表

<Input
  type="text"
  placeholder={"todo..."}
  value={todo}
  onChange={(e) => setTodo(e.target.value)}
  onKeyPress={(e) => {
    if (e.nativeEvent.keyCode === 13) {
      setTodo("");

      addTodo(Date.now(), todo);

      setTodos(getTodos());
    }
  }}
/>

实现todo list

1.遍历todos,显示每一个todo

2.点击时从localStorage删除todo

3.刷新todo列表

{
  todos &&
    todos.map((item) => {
      return (
        <div
          className="dishi-item"
          key={item.key}
          onClick={() => {
            delTodo(item.key);

            setTodos(getTodos());
          }}
        >
          {item.value}
        </div>
      );
    });
}

以上代码见: https://github.com/uikoo9/dishi-monorepo/tree/dishi-web%400.0.8

【总结】

以上就实现了一个基于localStorage本地存储数据的todo list,

最终效果地址: https://insistime.com/dishi-ls

最终代码见: https://github.com/uikoo9/dishi-monorepo/tree/localstorage

1.使用lerna管理项目, 一篇文章学会lerna

2.使用qiao-z开发nodejs服务端代码,  https://qiao-z.vincentqiao.com/#/

3.使用pm2部署nodejs服务端代码, 你所不知道的pm2

4.使用react开发前端项目, https://reactjs.org/

5.使用webpack构建前端项目,一篇文章学会Webpack5.x

6.使用qiao-webpack快速构建前端项目, https://qiao-webpack.vincentqiao.com/#/

7.使用腾讯云cos托管静态文件, https://code.insistime.com/#/qiao-cos-cli

8.使用localStorage保存本地数据,一篇文章学会localStorage

9.使用qiao.ls.js操作localStorage数据, https://code.insistime.com/#/qiao.ls.js

相关推荐

小巧的JS测试框架:AVA

【前言】 常见的JS测试框架有Jest,Mocha等, 今天介绍一个小巧的JS测试框架:ava, https://github.com/avajs/ava

规范的代码提交:Conventional Commits

【前言】 本文介绍如何提交规范的commit msg, 规范的commit msg可以看这个网站: https://www.conventionalcommits.org/en/v1.0.0/ 【commitizen】 可以手动提交符合规范的commit msg,如下 手动提交符合规范的msg比较麻

一篇文章学会IndexedDB

【简介】 IndexedDB,web端可以直接使用的数据库,详见: https://developer.mozilla.org/zhCN/docs/Web/API/IndexedDB\API 【IndexedDB vs LocalStorage】 之前介绍了LocalStorage:一篇文章学会lo

初始化前端Monorepos项目

【前言】 本文记录初始化一个前端Monorepos项目的过程 【LICENSE】 如果是开源项目, 需要添加LICENSE, 一般推荐使用MIT LICENSE, 模板如下, 其中copyright那一行, 可以替换为自己的信息。 【git】 git的一些基础设置 设置git账号信息 配置gitig

一篇文章判断用户是否在线

【前言】 如何判断用户在线,而不是用户网络是否连通, 在线:连网,可以访问internet 连通:连网,不能访问internet 【是否在线】 如上,判断是否在线,需要检测是否可以访问internet nodejs 在nodejs下,可以通过ping一些常见的域名来确定, 这里封装了一个工具, ht

一篇文章学会LocalStorage

【简介】 LocalStorage,即本地存储,详见: https://developer.mozilla.org/zhCN/docs/Web/API/Window/localStorage 【cookie vs LocalStorage】 服务端是否可以获取? cookie:服务端可以获取,每次请

mantine-ui快速上手

【前言】 2023年,前端开发的ui框架应该用哪个呢, 一些基本的诉求: 1.支持pc和移动端 2.支持黑夜&白天主题切换 3.组件丰富 4.支持react 4是技术栈选择,非通用 按以上要求在github上快速搜索下react相关ui库, 从start数,issues数,最后commit时间等维度

前端Monorepos项目使用npm-workspaces

【前言】 之前一直使用 lerna 来管理前端 monorepos 项目, 今天升级 lerna 后发现不支持 bootstrap 命令了, 替换为了 npm 的 workspaces 相关命令。 【lerna bootstrap】 lerna 的相关使用可以看这篇文章, 一文学会用Lerna管理多

Nx-VS-Lerna

【前言】 nx和lerna都是优秀的monorepos工具, 本文来对比一下两者的不同, https://nx.dev/ https://lerna.js.org/ 对比之前可以先看下面两篇文章, 了解nx和lerna的基本使用, 一文学会用Lerna管理多个npm包 强大的构建系统:NX 【任务执

强大的构建系统:NX

【前言】 nx是一个强大的构建系统, 这么说可能比较模糊, 本文实践一个项目,带大家了解nx, 感兴趣的也可以自己探索: https://nx.dev/ nx一些典型的应用场景: 1.基于package的monorepo管理 2.完整的前端项目管理 3.react,angular等项目管理 4.no

一篇文章了解JS并行任务

【前言】 在开发过程中大部分场景是顺序执行代码, 也有场景要求并行执行多个任务, 本文研究下如何高效的并行执行任务。 【并行场景】 常见并行执行任务的场景 1.并行执行多个请求 2.并行下载文件 【并行任务】 上述场景中任务的共同点是 1.多个任务没有依赖关系 2.多个任务完成耗时不确定 3.要求最

一篇文章学会Webpack5.x

【前言】 Web前端构建离不开webpack, 众所周知webpack的配置很多很复杂, 甚至可以设置“webpack配置工程师”, 本文抓住webpack核心概念, 和业务开发中常用配置进行讲解, 争取一篇文章学会webpack使用和配置。 【常用文档】 webpack官网 webpack手册:可

© 2026 vincentqiao.com . 保留所有权利。