【腾讯云Cloud Studio 实战训练营】深入解析Cloud Studio—React 快速构建点餐页面

序言

运气不会凭空而来,只有当你足够努力的时候,才会足够幸运。

文章标记颜色说明:

  • 黄色:重要标题
  • 红色:用来标记结论
  • 绿色:用来标记论点
  • 蓝色:用来标记论点

腾讯云CloudStudio是一款基于云端的集成开发环境(IDE),它可以让开发人员在任何地方、任何时间使用互联网访问和编写代码,而无需安装任何软件或工具。

在本文中,将详细介绍CloudStudio的

  • CloudStudio功能特点
  • 编辑器功能特点
  • 其他功能介绍
  • CloudStudio从0到1项目实战
  • 总结&展望

希望这篇文章能让你不仅有一定的收获,而且可以愉快的学习,如果有什么建议,都可以留言和我交流

 1 功能特点

CloudStudio是一款基于云端的集成开发环境(IDE),它提供了许多先进的特点和功能,可以帮助我们更加高效、灵活地进行软件开发和测试。

下面是CloudStudio的详细特点和功能:

  • 多语言支持
  • 无需安装
  • 云端存储
  • 智能编码
  • 版本控制
  • 丰富的插件生态
  • 高度可定制
  • 高度安全
  • 易于扩展
  • 轻量级

官网地址:cloudstudio 

  

1.1 多语言支持

CloudStudio支持多种编程语言和框架。

这意味着我们可以在同一个IDE中进行多种不同语言的开发工作,无需切换到不同的工具或环境。

CloudStudio支持多种编程语言和框架,包括但不限于以下几种:

  1. Java
  2. Python
  3. Node.js
  4. Kotlin
  5. Scala
  6. React
  7. Vue.js
  8. Angular
  9. Ruby
  10. PHP

除了上述编程语言和框架,CloudStudio还支持其他一些编程语言和框架。

CloudStudio支持多种编程语言和框架,可以满足不同类型的开发人员的需求。

如果需要使用其他编程语言或框架,也可以考虑使用CloudStudio的插件或自定义开发工具来满足对应的需求。

1.2 无需安装

CloudStudio是基于云端的IDE,无需在本地计算机上安装任何软件或工具。我们可以随时随地使用任何设备进行开发,无需担心软件安装和配置的问题。

访问地址:cloudstudio

1.3 云端存储

CloudStudio将代码和项目存储在云端,我们可以在任意设备上访问和编辑代码,无需担心数据丢失或备份。

此外,云端存储还可以帮助开发团队更好地协作和共享代码。

在个人设置有CODING GitHub账号关联设置

1.4 智能编码

CloudStudio内置了智能编码功能,可以提供代码补全、自动修复、重构等功能,帮助我们更加高效地编写代码。

此外,智能编码还可以提高代码的质量和可维护性。

1.5 版本控制

CloudStudio集成了Git版本控制系统,可以帮助我们轻松管理和维护自己的代码库。

我们可以使用Git来跟踪代码的变化、协作开发、管理分支和合并请求等。

1.6 丰富的插件生态

CloudStudio支持第三方插件,可以帮助我们扩展和定制IDE的功能。

这些插件可以提供额外的语言支持、调试器、自动化工具等,使得我们可以根据自己的需求进行个性化的设置。

1.7 高度可定制

CloudStudio提供了许多可定制的选项和设置,可以帮助我们根据自己的需求进行个性化设置,如修改主题、字体、缩进等。

1.8 高度安全

CloudStudio采用了多层安全措施,保障代码和数据的安全性。CloudStudio的数据存储和传输都采用了加密技术,确保数据不被黑客或恶意软件攻击。

1.9 易于扩展

CloudStudio具有可扩展性,可以根据需要添加新的工具、插件和库。开发人员可以使用CloudStudio的API和SDK来创建自己的插件和工具,以满足个性化需求。

1.10轻量级

CloudStudio是一个轻量级的IDE,可以快速启动和运行。这意味着开发人员可以更快地开始编写代码并运行项目,提高开发效率。

总结 

总之,CloudStudio是一款功能强大、安全稳定、易于扩展、轻量级的云端IDE,可以帮助我们更好地管理和维护他们的代码。

如果需要高效、灵活开发,CloudStudio是一个值得尝试的工具。

2 编辑器功能特点

以下是CloudStudio的代码编辑器支持的一些主要功能:

  1. 语法高亮
  2. 代码自动补全
  3. 自动缩进
  4. 多光标编辑
  5. 代码折叠
  6. 查找和替换
  7. 代码导航
  8. 快速预览
  9. 代码格式化

2.1 语法高亮

代码编辑器能够根据所使用的编程语言,自动高亮显示不同的语法元素,以帮助我们更好地理解代码结构。

2.2 代码自动补全

当输入代码时,编辑器会智能地提供代码补全建议,以帮助我们更快地编写代码。

这包括关键字、方法名、类名、变量名等。当按下Tab键时,编辑器会自动插入最佳建议。

2.3 自动缩进

代码编辑器会根据我们的编程语言和代码结构自动缩进,以更好地组织代码,并提高代码的可读性。

当然,也支持手动调整缩进。

2.4 多光标编辑

代码编辑器支持多光标编辑,可以同时在多个位置插入或编辑文本。只需按住Ctrl键并单击文本即可创建多个光标。

2.5 代码折叠

代码编辑器支持代码折叠,可以将代码块折叠起来,以便更好地浏览和编辑代码。您只需单击代码行号旁边的折叠图标即可折叠代码块。

2.6 查找和替换

代码编辑器支持查找和替换功能,可以帮助您快速查找并替换代码中的文本。您可以使用快捷键Ctrl+F(查找)和Ctrl+H(替换)。

2.7 代码导航

代码编辑器支持代码导航功能,可以帮助您快速浏览代码文件,并跳转到您需要的代码行。您可以使用快捷键Ctrl+Shift+O来打开文件导航器。

2.8 快速预览

代码编辑器支持快速预览功能,可以让您在不离开编辑器的情况下查看代码文件的内容。

只需单击文件名旁边的查看图标即可。

2.9 代码格式化

代码编辑器支持代码格式化功能,可以自动调整代码缩进、空格和换行等格式,以提高代码的可读性和一致性。

可以使用快捷键Ctrl+Shift+F来格式化代码。

2.10 总结 

总之,CloudStudio的代码编辑器是一个功能强大、易于使用的工具,可以帮助您更好地编写、阅读和维护代码。

如果您是一个需要高效、准确编码的开发人员,CloudStudio的代码编辑器是您的最佳选择。

3 其他功能

3.1 个人设置

个人设置包括:

  • SSH公钥
  • GIT代理
  • 关联账号
  • 实名认证
  • 环境变量

如下图示例,可根据自己的需要进行设置

GIT代理 

 关联账号

3.2 费用中心

费用中心包括三个模块:

  • 账户概览
  • 购买账单
  • 资源用量

这个模块主要是查看自己在平台的费用使用以及资源相关内容

进入费用中心

点击账号下面这个图标,就可以进入费用中心

账户概览 

资源用量

4 项目实战

这个项目会用云 IDE Cloud Studio 快速搭建,并开发还原一个移动端 React H5 的简版点餐系统页面。

从 0 到 1 体验云 Cloud Studio 给项目带来的优势。

4.1 注册账号

打开官方链接,注册可以使用三种方式:

  • CODEING
  • 微信
  • GitHub

我选择的是CODEING,需要先输入coding域名,

输入域名之后,进入下界面 ,选择你的coding账号方式,进行扫码。

  

如果你没有coding账号,需要先去注册一个,然后再进行登录。

coding官网地址:coding

 4.2 登录成功

 扫码之后,正产情况就会成功登录,界面如下 ,这里可以看到提供了很多模板:

  • 常用模板
  • 框架模板
  • 云原生模板
  • 建站模板

可以根据自己的需求,选择对应的模板。

4.3 框架初始化

1. 选择框架模板

因为这个项目使用的是React框架,所以我们可以选择这个框架,创建工作空间 

2 创建工作空间

3 代码初始化

空间启动成功中行,可以看到初始化左侧代码后,控制台会安装依赖及启动一个 React 简单的模板项目。

 

 4. 项目启动

在项目当前目录下,执行项目启动,执行之后,可看到下图,则说明项目初始化成功

yarn 
yarn start

4.4 安装依赖

下面进行相关依赖安装

 1. 安装 antd-mobile

安装命令
yarn add antd-mobile@^5.32.0

 安装成功

 

2. 安装 Less

 安装命令
yarn add -D less@^3.12.2 less-loader@^7.0.1

 安装成功

 3  修改webpack 配置文件

执行命令
yarn eject

输入 'y' 后,项目会自动进行解构操作。

完成命令之后,项目根目录会出现一个config文件夹,里面是一些配置相关的脚本,也可以看到 package.json 中多了很多属性值,如 "dependencies".

操作完成,会看到如下图:

 4.5 代码修改

找到 config/webpack.config.js 文件,找到第60行左右,这块是设置 css 相关的代码。

增加less配置:可以复制一下sass的代码,改为less

// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
// 新增加 Less 代码
const lessRegex = /\.(less)$/;
const lessModuleRegex = /\.module\.(less)$/;

 继续向下搜索sass,位置在 504 行左右,能够找到以下代码。

 和之前配置一样,仿照sass的配置,进行less的配置。

// less
{
  test: lessRegex,  // 有改动
  exclude: lessModuleRegex,  // 有改动
  use: getStyleLoaders(
    {
      importLoaders: 3,
      sourceMap: isEnvProduction
        ? shouldUseSourceMap
        : isEnvDevelopment,
    },
    'less-loader'  // 有改动
  ),
  sideEffects: true,
},
{
  test: lessModuleRegex,  // 有改动
  use: getStyleLoaders(
    {
      importLoaders: 3,
      sourceMap: isEnvProduction
        ? shouldUseSourceMap
        : isEnvDevelopment,
      modules: {
        getLocalIdent: getCSSModuleLocalIdent,
      },
    },
    'less-loader'  // 有改动
  ),
},
webpack.config.js 完整代码

复制下面代码可以直接替换webpack.config.js

'use strict';

const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const resolve = require('resolve');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const ESLintPlugin = require('eslint-webpack-plugin');
const paths = require('./paths');
const modules = require('./modules');
const getClientEnvironment = require('./env');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
const ForkTsCheckerWebpackPlugin =
  process.env.TSC_COMPILE_ON_ERROR === 'true'
    ? require('react-dev-utils/ForkTsCheckerWarningWebpackPlugin')
    : require('react-dev-utils/ForkTsCheckerWebpackPlugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash');

// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

const reactRefreshRuntimeEntry = require.resolve('react-refresh/runtime');
const reactRefreshWebpackPluginRuntimeEntry = require.resolve(
  '@pmmmwh/react-refresh-webpack-plugin'
);
const babelRuntimeEntry = require.resolve('babel-preset-react-app');
const babelRuntimeEntryHelpers = require.resolve(
  '@babel/runtime/helpers/esm/assertThisInitialized',
  { paths: [babelRuntimeEntry] }
);
const babelRuntimeRegenerator = require.resolve('@babel/runtime/regenerator', {
  paths: [babelRuntimeEntry],
});

// Some apps do not need the benefits of saving a web request, so not inlining the chunk
// makes for a smoother build process.
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';

const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === 'true';
const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === 'true';

const imageInlineSizeLimit = parseInt(
  process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
);

// Check if TypeScript is setup
const useTypeScript = fs.existsSync(paths.appTsConfig);

// Check if Tailwind config exists
const useTailwind = fs.existsSync(
  path.join(paths.appPath, 'tailwind.config.js')
);

// Get the path to the uncompiled service worker (if it exists).
const swSrc = paths.swSrc;

// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;

const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;

const hasJsxRuntime = (() => {
  if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
    return false;
  }

  try {
    require.resolve('react/jsx-runtime');
    return true;
  } catch (e) {
    return false;
  }
})();

// This is the production and development configuration.
// It is focused on developer experience, fast rebuilds, and a minimal bundle.
module.exports = function (webpackEnv) {
  const isEnvDevelopment = webpackEnv === 'development';
  const isEnvProduction = webpackEnv === 'production';

  // Variable used for enabling profiling in Production
  // passed into alias object. Uses a flag if passed into the build command
  const isEnvProductionProfile =
    isEnvProduction && process.argv.includes('--profile');

  // We will provide `paths.publicUrlOrPath` to our app
  // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
  // Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
  // Get environment variables to inject into our app.
  const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));

  const shouldUseReactRefresh = env.raw.FAST_REFRESH;

  // common function to get style loaders
  const getStyleLoaders = (cssOptions, preProcessor) => {
    const loaders = [
      isEnvDevelopment && require.resolve('style-loader'),
      isEnvProduction && {
        loader: MiniCssExtractPlugin.loader,
        // css is located in `static/css`, use '../../' to locate index.html folder
        // in production `paths.publicUrlOrPath` can be a relative path
        options: paths.publicUrlOrPath.startsWith('.')
          ? { publicPath: '../../' }
          : {},
      },
      {
        loader: require.resolve('css-loader'),
        options: cssOptions,
      },
      {
        // Options for PostCSS as we reference these options twice
        // Adds vendor prefixing based on your specified browser support in
        // package.json
        loader: require.resolve('postcss-loader'),
        options: {
          postcssOptions: {
            // Necessary for external CSS imports to work
            // https://github.com/facebook/create-react-app/issues/2677
            ident: 'postcss',
            config: false,
            plugins: !useTailwind
              ? [
                  'postcss-flexbugs-fixes',
                  [
                    'postcss-preset-env',
                    {
                      autoprefixer: {
                        flexbox: 'no-2009',
                      },
                      stage: 3,
                    },
                  ],
                  // Adds PostCSS Normalize as the reset css with default options,
                  // so that it honors browserslist config in package.json
                  // which in turn let's users customize the target behavior as per their needs.
                  'postcss-normalize',
                ]
              : [
                  'tailwindcss',
                  'postcss-flexbugs-fixes',
                  [
                    'postcss-preset-env',
                    {
                      autoprefixer: {
                        flexbox: 'no-2009',
                      },
                      stage: 3,
                    },
                  ],
                ],
          },
          sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
        },
      },
    ].filter(Boolean);
    if (preProcessor) {
      loaders.push(
        {
          loader: require.resolve('resolve-url-loader'),
          options: {
            sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
            root: paths.appSrc,
          },
        },
        {
          loader: require.resolve(preProcessor),
          options: {
            sourceMap: true,
          },
        }
      );
    }
    return loaders;
  };

  return {
    target: ['browserslist'],
    // Webpack noise constrained to errors and warnings
    stats: 'errors-warnings',
    mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
    // Stop compilation early in production
    bail: isEnvProduction,
    devtool: isEnvProduction
      ? shouldUseSourceMap
        ? 'source-map'
        : false
      : isEnvDevelopment && 'cheap-module-source-map',
    // These are the "entry points" to our application.
    // This means they will be the "root" imports that are included in JS bundle.
    entry: paths.appIndexJs,
    output: {
      // The build folder.
      path: paths.appBuild,
      // Add /* filename */ comments to generated require()s in the output.
      pathinfo: isEnvDevelopment,
      // There will be one main bundle, and one file per asynchronous chunk.
      // In development, it does not produce real files.
      filename: isEnvProduction
        ? 'static/js/[name].[contenthash:8].js'
        : isEnvDevelopment && 'static/js/bundle.js',
      // There are also additional JS chunk files if you use code splitting.
      chunkFilename: isEnvProduction
        ? 'static/js/[name].[contenthash:8].chunk.js'
        : isEnvDevelopment && 'static/js/[name].chunk.js',
      assetModuleFilename: 'static/media/[name].[hash][ext]',
      // webpack uses `publicPath` to determine where the app is being served from.
      // It requires a trailing slash, or the file assets will get an incorrect path.
      // We inferred the "public path" (such as / or /my-project) from homepage.
      publicPath: paths.publicUrlOrPath,
      // Point sourcemap entries to original disk location (format as URL on Windows)
      devtoolModuleFilenameTemplate: isEnvProduction
        ? info =>
            path
              .relative(paths.appSrc, info.absoluteResourcePath)
              .replace(/\\/g, '/')
        : isEnvDevelopment &&
          (info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
    },
    cache: {
      type: 'filesystem',
      version: createEnvironmentHash(env.raw),
      cacheDirectory: paths.appWebpackCache,
      store: 'pack',
      buildDependencies: {
        defaultWebpack: ['webpack/lib/'],
        config: [__filename],
        tsconfig: [paths.appTsConfig, paths.appJsConfig].filter(f =>
          fs.existsSync(f)
        ),
      },
    },
    infrastructureLogging: {
      level: 'none',
    },
    optimization: {
      minimize: isEnvProduction,
      minimizer: [
        // This is only used in production mode
        new TerserPlugin({
          terserOptions: {
            parse: {
              // We want terser to parse ecma 8 code. However, we don't want it
              // to apply any minification steps that turns valid ecma 5 code
              // into invalid ecma 5 code. This is why the 'compress' and 'output'
              // sections only apply transformations that are ecma 5 safe
              // https://github.com/facebook/create-react-app/pull/4234
              ecma: 8,
            },
            compress: {
              ecma: 5,
              warnings: false,
              // Disabled because of an issue with Uglify breaking seemingly valid code:
              // https://github.com/facebook/create-react-app/issues/2376
              // Pending further investigation:
              // https://github.com/mishoo/UglifyJS2/issues/2011
              comparisons: false,
              // Disabled because of an issue with Terser breaking valid code:
              // https://github.com/facebook/create-react-app/issues/5250
              // Pending further investigation:
              // https://github.com/terser-js/terser/issues/120
              inline: 2,
            },
            mangle: {
              safari10: true,
            },
            // Added for profiling in devtools
            keep_classnames: isEnvProductionProfile,
            keep_fnames: isEnvProductionProfile,
            output: {
              ecma: 5,
              comments: false,
              // Turned on because emoji and regex is not minified properly using default
              // https://github.com/facebook/create-react-app/issues/2488
              ascii_only: true,
            },
          },
        }),
        // This is only used in production mode
        new CssMinimizerPlugin(),
      ],
    },
    resolve: {
      // This allows you to set a fallback for where webpack should look for modules.
      // We placed these paths second because we want `node_modules` to "win"
      // if there are any conflicts. This matches Node resolution mechanism.
      // https://github.com/facebook/create-react-app/issues/253
      modules: ['node_modules', paths.appNodeModules].concat(
        modules.additionalModulePaths || []
      ),
      // These are the reasonable defaults supported by the Node ecosystem.
      // We also include JSX as a common component filename extension to support
      // some tools, although we do not recommend using it, see:
      // https://github.com/facebook/create-react-app/issues/290
      // `web` extension prefixes have been added for better support
      // for React Native Web.
      extensions: paths.moduleFileExtensions
        .map(ext => `.${ext}`)
        .filter(ext => useTypeScript || !ext.includes('ts')),
      alias: {
        // Support React Native Web
        // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
        'react-native': 'react-native-web',
        // Allows for better profiling with ReactDevTools
        ...(isEnvProductionProfile && {
          'react-dom$': 'react-dom/profiling',
          'scheduler/tracing': 'scheduler/tracing-profiling',
        }),
        ...(modules.webpackAliases || {}),
      },
      plugins: [
        // Prevents users from importing files from outside of src/ (or node_modules/).
        // This often causes confusion because we only process files within src/ with babel.
        // To fix this, we prevent you from importing files out of src/ -- if you'd like to,
        // please link the files into your node_modules/ and let module-resolution kick in.
        // Make sure your source files are compiled, as they will not be processed in any way.
        new ModuleScopePlugin(paths.appSrc, [
          paths.appPackageJson,
          reactRefreshRuntimeEntry,
          reactRefreshWebpackPluginRuntimeEntry,
          babelRuntimeEntry,
          babelRuntimeEntryHelpers,
          babelRuntimeRegenerator,
        ]),
      ],
    },
    module: {
      strictExportPresence: true,
      rules: [
        // Handle node_modules packages that contain sourcemaps
        shouldUseSourceMap && {
          enforce: 'pre',
          exclude: /@babel(?:\/|\\{1,2})runtime/,
          test: /\.(js|mjs|jsx|ts|tsx|css)$/,
          loader: require.resolve('source-map-loader'),
        },
        {
          // "oneOf" will traverse all following loaders until one will
          // match the requirements. When no loader matches it will fall
          // back to the "file" loader at the end of the loader list.
          oneOf: [
            // TODO: Merge this config once `image/avif` is in the mime-db
            // https://github.com/jshttp/mime-db
            {
              test: [/\.avif$/],
              type: 'asset',
              mimetype: 'image/avif',
              parser: {
                dataUrlCondition: {
                  maxSize: imageInlineSizeLimit,
                },
              },
            },
            // "url" loader works like "file" loader except that it embeds assets
            // smaller than specified limit in bytes as data URLs to avoid requests.
            // A missing `test` is equivalent to a match.
            {
              test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
              type: 'asset',
              parser: {
                dataUrlCondition: {
                  maxSize: imageInlineSizeLimit,
                },
              },
            },
            {
              test: /\.svg$/,
              use: [
                {
                  loader: require.resolve('@svgr/webpack'),
                  options: {
                    prettier: false,
                    svgo: false,
                    svgoConfig: {
                      plugins: [{ removeViewBox: false }],
                    },
                    titleProp: true,
                    ref: true,
                  },
                },
                {
                  loader: require.resolve('file-loader'),
                  options: {
                    name: 'static/media/[name].[hash].[ext]',
                  },
                },
              ],
              issuer: {
                and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
              },
            },
            // Process application JS with Babel.
            // The preset includes JSX, Flow, TypeScript, and some ESnext features.
            {
              test: /\.(js|mjs|jsx|ts|tsx)$/,
              include: paths.appSrc,
              loader: require.resolve('babel-loader'),
              options: {
                customize: require.resolve(
                  'babel-preset-react-app/webpack-overrides'
                ),
                presets: [
                  [
                    require.resolve('babel-preset-react-app'),
                    {
                      runtime: hasJsxRuntime ? 'automatic' : 'classic',
                    },
                  ],
                ],
                
                plugins: [
                  isEnvDevelopment &&
                    shouldUseReactRefresh &&
                    require.resolve('react-refresh/babel'),
                ].filter(Boolean),
                // This is a feature of `babel-loader` for webpack (not Babel itself).
                // It enables caching results in ./node_modules/.cache/babel-loader/
                // directory for faster rebuilds.
                cacheDirectory: true,
                // See #6846 for context on why cacheCompression is disabled
                cacheCompression: false,
                compact: isEnvProduction,
              },
            },
            // Process any JS outside of the app with Babel.
            // Unlike the application JS, we only compile the standard ES features.
            {
              test: /\.(js|mjs)$/,
              exclude: /@babel(?:\/|\\{1,2})runtime/,
              loader: require.resolve('babel-loader'),
              options: {
                babelrc: false,
                configFile: false,
                compact: false,
                presets: [
                  [
                    require.resolve('babel-preset-react-app/dependencies'),
                    { helpers: true },
                  ],
                ],
                cacheDirectory: true,
                // See #6846 for context on why cacheCompression is disabled
                cacheCompression: false,
                
                // Babel sourcemaps are needed for debugging into node_modules
                // code.  Without the options below, debuggers like VSCode
                // show incorrect code and set breakpoints on the wrong lines.
                sourceMaps: shouldUseSourceMap,
                inputSourceMap: shouldUseSourceMap,
              },
            },
            // "postcss" loader applies autoprefixer to our CSS.
            // "css" loader resolves paths in CSS and adds assets as dependencies.
            // "style" loader turns CSS into JS modules that inject <style> tags.
            // In production, we use MiniCSSExtractPlugin to extract that CSS
            // to a file, but in development "style" loader enables hot editing
            // of CSS.
            // By default we support CSS Modules with the extension .module.css
            {
              test: cssRegex,
              exclude: cssModuleRegex,
              use: getStyleLoaders({
                importLoaders: 1,
                sourceMap: isEnvProduction
                  ? shouldUseSourceMap
                  : isEnvDevelopment,
                modules: {
                  mode: 'icss',
                },
              }),
              // Don't consider CSS imports dead code even if the
              // containing package claims to have no side effects.
              // Remove this when webpack adds a warning or an error for this.
              // See https://github.com/webpack/webpack/issues/6571
              sideEffects: true,
            },
            // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
            // using the extension .module.css
            {
              test: cssModuleRegex,
              use: getStyleLoaders({
                importLoaders: 1,
                sourceMap: isEnvProduction
                  ? shouldUseSourceMap
                  : isEnvDevelopment,
                modules: {
                  mode: 'local',
                  getLocalIdent: getCSSModuleLocalIdent,
                },
              }),
            },
            // Opt-in support for SASS (using .scss or .sass extensions).
            // By default we support SASS Modules with the
            // extensions .module.scss or .module.sass
            {
              test: sassRegex,
              exclude: sassModuleRegex,
              use: getStyleLoaders(
                {
                  importLoaders: 3,
                  sourceMap: isEnvProduction
                    ? shouldUseSourceMap
                    : isEnvDevelopment,
                  modules: {
                    mode: 'icss',
                  },
                },
                'sass-loader'
              ),
              // Don't consider CSS imports dead code even if the
              // containing package claims to have no side effects.
              // Remove this when webpack adds a warning or an error for this.
              // See https://github.com/webpack/webpack/issues/6571
              sideEffects: true,
            },
            // Adds support for CSS Modules, but using SASS
            // using the extension .module.scss or .module.sass
            {
              test: sassModuleRegex,
              use: getStyleLoaders(
                {
                  importLoaders: 3,
                  sourceMap: isEnvProduction
                    ? shouldUseSourceMap
                    : isEnvDevelopment,
                  modules: {
                    mode: 'local',
                    getLocalIdent: getCSSModuleLocalIdent,
                  },
                },
                'sass-loader'
              ),
            },
            // less
              {
                test: lessRegex,  // 有改动
                exclude: lessModuleRegex,  // 有改动
                use: getStyleLoaders(
                  {
                    importLoaders: 3,
                    sourceMap: isEnvProduction
                      ? shouldUseSourceMap
                      : isEnvDevelopment,
                  },
                  'less-loader'  // 有改动
                ),
                sideEffects: true,
              },
              {
                test: lessModuleRegex,  // 有改动
                use: getStyleLoaders(
                  {
                    importLoaders: 3,
                    sourceMap: isEnvProduction
                      ? shouldUseSourceMap
                      : isEnvDevelopment,
                    modules: {
                      getLocalIdent: getCSSModuleLocalIdent,
                    },
                  },
                  'less-loader'  // 有改动
                ),
              },
            // "file" loader makes sure those assets get served by WebpackDevServer.
            // When you `import` an asset, you get its (virtual) filename.
            // In production, they would get copied to the `build` folder.
            // This loader doesn't use a "test" so it will catch all modules
            // that fall through the other loaders.
            {
              // Exclude `js` files to keep "css" loader working as it injects
              // its runtime that would otherwise be processed through "file" loader.
              // Also exclude `html` and `json` extensions so they get processed
              // by webpacks internal loaders.
              exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
              type: 'asset/resource',
            },
            // ** STOP ** Are you adding a new loader?
            // Make sure to add the new loader(s) before the "file" loader.
          ],
        },
      ].filter(Boolean),
    },
    plugins: [
      // Generates an `index.html` file with the <script> injected.
      new HtmlWebpackPlugin(
        Object.assign(
          {},
          {
            inject: true,
            template: paths.appHtml,
          },
          isEnvProduction
            ? {
                minify: {
                  removeComments: true,
                  collapseWhitespace: true,
                  removeRedundantAttributes: true,
                  useShortDoctype: true,
                  removeEmptyAttributes: true,
                  removeStyleLinkTypeAttributes: true,
                  keepClosingSlash: true,
                  minifyJS: true,
                  minifyCSS: true,
                  minifyURLs: true,
                },
              }
            : undefined
        )
      ),
      // Inlines the webpack runtime script. This script is too small to warrant
      // a network request.
      // https://github.com/facebook/create-react-app/issues/5358
      isEnvProduction &&
        shouldInlineRuntimeChunk &&
        new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
      // Makes some environment variables available in index.html.
      // The public URL is available as %PUBLIC_URL% in index.html, e.g.:
      // <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
      // It will be an empty string unless you specify "homepage"
      // in `package.json`, in which case it will be the pathname of that URL.
      new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
      // This gives some necessary context to module not found errors, such as
      // the requesting resource.
      new ModuleNotFoundPlugin(paths.appPath),
      // Makes some environment variables available to the JS code, for example:
      // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
      // It is absolutely essential that NODE_ENV is set to production
      // during a production build.
      // Otherwise React will be compiled in the very slow development mode.
      new webpack.DefinePlugin(env.stringified),
      // Experimental hot reloading for React .
      // https://github.com/facebook/react/tree/main/packages/react-refresh
      isEnvDevelopment &&
        shouldUseReactRefresh &&
        new ReactRefreshWebpackPlugin({
          overlay: false,
        }),
      // Watcher doesn't work well if you mistype casing in a path so we use
      // a plugin that prints an error when you attempt to do this.
      // See https://github.com/facebook/create-react-app/issues/240
      isEnvDevelopment && new CaseSensitivePathsPlugin(),
      isEnvProduction &&
        new MiniCssExtractPlugin({
          // Options similar to the same options in webpackOptions.output
          // both options are optional
          filename: 'static/css/[name].[contenthash:8].css',
          chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
        }),
      // Generate an asset manifest file with the following content:
      // - "files" key: Mapping of all asset filenames to their corresponding
      //   output file so that tools can pick it up without having to parse
      //   `index.html`
      // - "entrypoints" key: Array of files which are included in `index.html`,
      //   can be used to reconstruct the HTML if necessary
      new WebpackManifestPlugin({
        fileName: 'asset-manifest.json',
        publicPath: paths.publicUrlOrPath,
        generate: (seed, files, entrypoints) => {
          const manifestFiles = files.reduce((manifest, file) => {
            manifest[file.name] = file.path;
            return manifest;
          }, seed);
          const entrypointFiles = entrypoints.main.filter(
            fileName => !fileName.endsWith('.map')
          );

          return {
            files: manifestFiles,
            entrypoints: entrypointFiles,
          };
        },
      }),
      // Moment.js is an extremely popular library that bundles large locale files
      // by default due to how webpack interprets its code. This is a practical
      // solution that requires the user to opt into importing specific locales.
      // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
      // You can remove this if you don't use Moment.js:
      new webpack.IgnorePlugin({
        resourceRegExp: /^\.\/locale$/,
        contextRegExp: /moment$/,
      }),
      // Generate a service worker script that will precache, and keep up to date,
      // the HTML & assets that are part of the webpack build.
      isEnvProduction &&
        fs.existsSync(swSrc) &&
        new WorkboxWebpackPlugin.InjectManifest({
          swSrc,
          dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
          exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
          // Bump up the default maximum size (2mb) that's precached,
          // to make lazy-loading failure scenarios less likely.
          // See https://github.com/cra-template/pwa/issues/13#issuecomment-722667270
          maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
        }),
      // TypeScript type checking
      useTypeScript &&
        new ForkTsCheckerWebpackPlugin({
          async: isEnvDevelopment,
          typescript: {
            typescriptPath: resolve.sync('typescript', {
              basedir: paths.appNodeModules,
            }),
            configOverwrite: {
              compilerOptions: {
                sourceMap: isEnvProduction
                  ? shouldUseSourceMap
                  : isEnvDevelopment,
                skipLibCheck: true,
                inlineSourceMap: false,
                declarationMap: false,
                noEmit: true,
                incremental: true,
                tsBuildInfoFile: paths.appTsBuildInfoFile,
              },
            },
            context: paths.appPath,
            diagnosticOptions: {
              syntactic: true,
            },
            mode: 'write-references',
            // profile: true,
          },
          issue: {
            // This one is specifically to match during CI tests,
            // as micromatch doesn't match
            // '../cra-template-typescript/template/src/App.tsx'
            // otherwise.
            include: [
              { file: '../**/src/**/*.{ts,tsx}' },
              { file: '**/src/**/*.{ts,tsx}' },
            ],
            exclude: [
              { file: '**/src/**/__tests__/**' },
              { file: '**/src/**/?(*.){spec|test}.*' },
              { file: '**/src/setupProxy.*' },
              { file: '**/src/setupTests.*' },
            ],
          },
          logger: {
            infrastructure: 'silent',
          },
        }),
      !disableESLintPlugin &&
        new ESLintPlugin({
          // Plugin options
          extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
          formatter: require.resolve('react-dev-utils/eslintFormatter'),
          eslintPath: require.resolve('eslint'),
          failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
          context: paths.appSrc,
          cache: true,
          cacheLocation: path.resolve(
            paths.appNodeModules,
            '.cache/.eslintcache'
          ),
          // ESLint class options
          cwd: paths.appPath,
          resolvePluginsRelativeTo: __dirname,
          baseConfig: {
            extends: [require.resolve('eslint-config-react-app/base')],
            rules: {
              ...(!hasJsxRuntime && {
                'react/react-in-jsx-scope': 'error',
              }),
            },
          },
        }),
    ].filter(Boolean),
    // Turn off performance processing because we utilize
    // our own hints via the FileSizeReporter
    performance: false,
  };
};

4.6 安装 normalize

安装命令

yarn add -D normalize.css@^8.0.1

安装成功 

4.7 上传素材

下载对应的img,解压之后,上传到src文件夹下面:

下载地址:素材-img

 

4.8 替换App.js主文件 

将原本的App.js直接替换为下面内容

import './App.css';
import React, { useState } from 'react'
import { NavBar, Toast, Swiper, SideBar, TabBar, Badge } from 'antd-mobile'
import {
  AppOutline,
  ExclamationShieldOutline,
  UnorderedListOutline,
  UserOutline,
} from 'antd-mobile-icons'
import BannerImg from './img/banner.png'
import HotImg from './img/hot.png'
import Food1Img from './img/food1.png'
import Food2Img from './img/food2.png'
import CartImg from './img/cart.png'
import './index.less'
import "normalize.css"

function App() {
  const [activeKey, setActiveKey] = useState('1')

  const tabbars = [
    {
      key: 'home',
      title: '点餐',
      icon: <AppOutline />,
    },
    {
      key: 'todo',
      title: '购物车',
      icon: <UnorderedListOutline />,
      badge: '5',
    },
    {
      key: 'sale',
      title: '餐牌预告',
      icon: <ExclamationShieldOutline />,
    },
    {
      key: '我的',
      title: '我的',
      icon: <UserOutline />,
      badge: Badge.dot,
    },
  ]

  const back = () =>
    Toast.show({
      content: '欢迎进入点餐系统',
      duration: 1000,
    })


  const items = ['', '', '', ''].map((color, index) => (
    <Swiper.Item key={index}>
      <img style={{
        width: '100%'
      }} src={ BannerImg }></img>
    </Swiper.Item>
  ))

  const tabs =  [
    { key: '1', title: '热销' },
    { key: '2', title: '套餐' },
    { key: '3', title: '米饭' },
    { key: '4', title: '烧菜' },
    { key: '5', title: '汤' },
    { key: '6', title: '主食' },
    { key: '7', title: '饮料' },
  ]

  const productName = [
    '小炒黄牛肉',
    '芹菜肉丝炒香干',
    '番茄炒鸡蛋',
    '鸡汤',
    '酸菜鱼',
    '水煮肉片',
    '土豆炒肉片',
    '孜然肉片',
    '宫保鸡丁',
    '麻辣豆腐',
    '香椿炒鸡蛋',
    '豆角炒肉'
  ]
  const productList = productName.map((item, key) => {
    return {
      name: item,
      img: key % 2 === 1 ? Food1Img : Food2Img
    }
  })

  return (
    <div className="App">
      <NavBar onBack={back} style={{
        background: '#F0F0F0',
        fontWeight: 'bold'
      }}>点餐</NavBar>

      <div className='head-card'>
        <Swiper
          style={{
            '--border-radius': '8px',
          }}
          autoplay
          defaultIndex={1}
        >
          {items}
        </Swiper>
      </div>

      <div className='product-box'>
        <SideBar activeKey={activeKey} onChange={setActiveKey}>
          {tabs.map(item => (
            <SideBar.Item key={item.key} title={
              item.key === '1' ? <div>
              <div className='flex-center'>
                <img style={{
                  display: 'block',
                  width: '16px',
                  marginRight: '5px'
                }} src={ HotImg }></img>
                <div>{ item.title }</div>
              </div>
            </div> : item.title
            } />
          ))}
        </SideBar>
        <div className='product-right'>
          <div className='product-title'>热销</div>
          <div className='product-list'>
            {
              productList.map((item, key) => {
                return (
                  <div className='product-item'>
                    <div className='product-item-left'>
                      <img style={{
                        display: 'block',
                        width: '76px',
                        marginRight: '5px'
                      }} src={ item.img }></img>
                      <div className='product-item-left-info'>
                        <div>
                          <div className='product-item-left-info-name'>{ item.name }</div>
                          <div className='product-item-left-info-number'>月售{key + 1}0 赞{key * 5}</div>
                        </div>
                        <div className='product-item-left-info-price'>¥10</div>
                      </div>
                    </div>
                    <div className="cart">
                      <img style={{
                        display: 'block',
                        width: '30px',
                        marginRight: '5px'
                      }} src={ CartImg } onClick = { () =>
                        Toast.show({
                          content: '添加购物车成功'
                        }) }></img>
                    </div>
                  </div>
                )
              })
            }
          </div>
        </div>
      </div>

      <TabBar>
        {tabbars.map(item => (
          <TabBar.Item
            key={item.key}
            icon={item.icon}
            title={item.title}
            badge={item.badge}
          />
        ))}
      </TabBar>
    </div>
  );
}

export default App;
在 src 目录下,创建一个 index.less 文件,将以下 less 相关的代码复制到该文件中即可。

.head-card {
  padding: 10px 20px;
  box-sizing: border-box;
}

.flex-center {
  display: flex;
  align-items: center;
}

.product-box {
  display: flex;
  align-items: center;
  width: 100%;
  height: calc(100vh - 45px - 130px - 50px);
}

.product-right {
  flex: 1;
  height: 100%;
}

.product-title {
  font-family: PingFangSC-Regular;
  font-size: 14px;
  color: #000000;
  text-align: left;
  padding-bottom: 10px;
}

.product-list {
  height: calc(100% - 24px);
  overflow-y: auto;
}

.product-item {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-left: 10px;
  box-sizing: border-box;
  margin-bottom: 10px;
  &-left {
    display: flex;
    &-info {
      padding-left: 3px;
      box-sizing: border-box;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      &-name {
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: #000000;
        text-align: left;
      }
      &-number {
        padding-top: 3px;
        font-family: PingFangSC-Regular;
        font-size: 11px;
        color: #787878;
        text-align: left;
      }
      &-price {
        font-family: PingFangSC-Regular;
        font-size: 18px;
        color: #FF1800;
        text-align: left;
      }
    }
  }
}

.cart {
  position: absolute;
  right: 10px;
  bottom: 0;
}

4.9 启动项目

复制完成后,在控制台中输入 yarn dev即可启动该项目。 启动成功之后,如下图

  • Cloud Studio 内置预览插件,可以实时显示网页应用,当代码发生改变之后,预览窗口会自动刷新,即可在 Cloud Studio 内实时开发调试网页了
  • 本项目是移动端H5的项目,需要打开“toggle device”按钮查看样式。
  • 提供了二唯码在手机端进行调试。

4.10 代码提交

因为前面登录时使用的是coding,所以就直接推送到coding仓库了,当然也可以推送到github,需要绑定对应的账号,可以看下前面讲的关联账号内容。

填写README.md文件后,左边功能菜单区找到“源代码管理”,

  • 使用 git init 进行仓库初始化
  • 输入需要提交的message信息
  • 再点击"Commit"进行仓库提交

就可以完成代码的

可以查看代码提交记录,如下图

4.11 工作空间管理

1 关闭空间

如果不使用的时候,可以在开发空间控制台把空间关闭

2 删除空间

如果彻底不需要该工作空间之后,可以在停止空间之后,进行删除

5 总结

5.1 特点总结

 通过使用和项目实战,对于Cloud Studio,总结出以下特点:

  1. 云端开发:它一个基于云端的开发平台,我们可以通过 web 界面进行开发,不需要在本地安装任何开发环境。这样可以避免本地开发环境的配置和维护问题,并且可以随时随地进行开发。

  2. 多语言支持支持多种编程语言,包括 JavaScript、Python、Go、Java、C# 等。我们可以选择自己熟悉的编程语言进行开发。

  3. 集成开发环境提供了完整的集成开发环境,包括代码编辑器、调试器、终端等功能。用户可以在一个界面中完成所有的开发工作,无需切换不同的工具。

  4. 协作开发支持多人协作开发,多个用户可以在同一个项目中进行开发,并且可以实时编辑同一份代码。此外,Cloud Studio 还提供了团队协作工具,包括代码审查、问题跟踪等功能。

  5. 可扩展性:支持插件扩展,我们可以根据自己的需求安装和使用各种插件,扩展平台的功能和能力。

  6. 安全性提供了安全的开发环境,项目的代码和数据都存储在云端,可以避免本地数据丢失和泄露问题。

5.2 优化建议

使用下来,总结建议如下:

  1. 提供更加直观的导航栏和页面布局:当前网站的导航栏和页面布局较为简单,用户可能需要花费一些时间才能找到自己需要的功能。可以考虑重新设计导航栏和页面布局,提供更加直观和易于使用的界面。

  2. 提供更加详细的帮助和文档当前网站的帮助和文档较为简略,用户可能需要花费更多的时间和精力才能理解和使用平台的各种功能。可以考虑提供更加详细和全面的帮助和文档,帮助用户更好地使用平台。

  3. 支持更多的编程语言和框架:当前网站支持的编程语言和框架不能够满足所有用户的需求。可以考虑支持更多的编程语言和框架,提高平台的适用性和可扩展性。

  4. 提供更加优化的性能和稳定性:目前网站的性能和稳定性还有进一步提升的空间,有时候可能会出现一些卡顿和崩溃等问题。为了提高用户的使用体验,建议考虑优化平台的性能和稳定性。

6 投票 

  • 94
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 144
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 144
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜淡慕潇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值