Front-end combat: Build front-end H5 development environment

preface

The React stack has a smaller library of UI components than Vue. The well-known one is Antd, but it is aimed at PC terminal. Currently, the project is an H5 web page (it does not rule out making a PC terminal in the future). So Zarm was chosen.

Here again, it is not that Zarm is better than other mobile component libraries, but Zarm is more suitable for the bookkeeping project currently developed.

knowledge

  • Architecture toolsVite.
  • The front frameReactAnd routingreact-router-dom.
  • CSSPreloading deviceLess.
  • HTTPRequest libraryaxios.
  • Mobile resolution adaptationflexible.
  • Cross-domain proxy.

Initialize the Vite + React project

Vite officially provides two ways to initialize a project. One is shown below, and you can choose the front-end framework you want.

npm init @vitejs/app
Copy the code

The other option is to generate the project directly from the official template with one click:

# npm 6.x 
npm init @vitejs/app react-vite-h5 --template react 

# npm 7+, requires extra double lines: NPM init. vitejs/app react-viet-h5 -- --template reactCopy the code

I use the second method to initialize the project, as follows:

After installing node_modules, start the project with NPM run dev, as shown below, indicating success:

React-router-dom routing plugin is introduced

A project without a route is not a complete project, but a page. Real projects involve switching between various modules, and only when the functions of each module are combined can they be called a project.

Install react-router-dom as follows:

npm i react-router-dom -S
Copy the code

Add the pages directory under the project SRC directory to place the page components, add two new directories under the Pages directory respectively Index and About, add the following contents:

Index/index.jsx
import React from 'react'

export default function Index() {
  return <div>
    Index
  </div>
}

// About/index.jsx
import React from 'react'

export default function About() {
  return <div>
    About
  </div>
}
Copy the code

SRC /router/index.js config route array

// router/index.js
import Index from '.. /pages/Index'
import About from '.. /pages/About'

const routes = [
  {
    path: "/".component: Index
  },
  {
    path: "/about".component: About
  }
];

export default routes
Copy the code

App. JSX introduces routing configuration to switch browser path and display corresponding components:

// App.jsx
import React, { useState } from 'react'
import {
  BrowserRouter as Router,
  Switch,
  Route
} from "react-router-dom"
import routes from '.. /src/router'
function App() {
  return <Router>
    <Switch>
      {
        routes.map(route => <Route exact key={route.path} path={route.path}>
          <route.component />
        </Route>)}</Switch>
  </Router>
}

export default App
Copy the code

Start the project NPM run Dev as shown below:

Introduction of Zarm UI component library

First install it with the following command:

npm install zarm -S
Copy the code

Modify app.jsx code to introduce global styles and Chinese packages:

import React, { useState } from 'react'
import {
  BrowserRouter as Router,
  Switch,
  Route
} from "react-router-dom"

import { ConfigProvider } from 'zarm'
import zhCN from 'zarm/lib/config-provider/locale/zh_CN'
import 'zarm/dist/zarm.css'

import routes from '.. /src/router'
function App() {
  return <Router>
    <ConfigProvider primaryColor={'#007fff'} locale={zhCN}>
      <Switch>
        {
          routes.map(route => <Route exact key={route.path} path={route.path}>
            <route.component />
          </Route>)}</Switch>
    </ConfigProvider>
  </Router>
}

export default App
Copy the code

JSX /pages/Index/index.jsx /pages/Index/index.jsx

// Index/index.jsx
import React from 'react'
import { Button } from 'zarm'

export default function Index() {
  return <div>
    Index
    <Button theme='primary'>button</Button>
  </div>
}
Copy the code

Restart the project as follows:

Congratulations at this point 🎉, you have successfully introduced the component into the project.

Three. Small optimization

The component was introduced successfully, but there was one problem. I didn’t want all the component styles to be introduced at once, because the code would be redundant. I just needed to import the component styles I used and implement “import on demand”.

Let’s take a look at how big the static resources are after the package is done in this case. Run the command NPM run build, as shown below:

The CSS static resources are 168.22 KB after the package is completed. Try to configure “import on demand”.

Start by installing a plug-in:

npm i vite-plugin-style-import -D
Copy the code

Then add the following to the vite.config.js configuration file:

export default defineConfig({
  plugins: [reactRefresh(), styleImport(
    {
      libs: [{libraryName: 'zarm'.esModule: true.resolveStyle: (name) = > {
            return `zarm/es/${name}/style/css`; },}]})],Copy the code

After the package is finished, the CSS mentions range from 168.22 KB -> 35.22 KB. This approach is also one of front-end performance optimization.

4. Configure the CSS preprocessor Less

Less is used in the project as the CSS preprocessor, which can set variables and some nested logic to facilitate the style writing of the project.

Install the less plug-in package, NPM I less-d, because the configuration uses less, and javascriptEnabled must be set to true to support less inline JS.

Modify vite.config.js as follows:

{
  plugins: [...].css: {
    modules: {
      localsConvention: 'dashesOnly'
    },
    preprocessorOptions: {
      less: {
        // Support inline JavaScript
        javascriptEnabled: true,}}},}Copy the code

I also added CSS Modules configuration, so I don’t have to worry about the risk of custom style names in the project. Try adding style file style.module.less under /pages/Index. Add it to /pages/Index/index.jsx as follows:

.index { 
  span { 
    color: red; }}Copy the code
// Index/index.jsx
import React from 'react'
import { Button } from 'zarm'

import s from './style.module.less'

export default function Index() {
  return <div className={s.index}>
    <span>style</span>
    <Button theme='primary'>button</Button>
  </div>
}
Copy the code

At this point I can only congratulate you again, Less has been successfully introduced.

5. Mobile terminal project ADAPTS rem

For example, if you have a width of 10px, the ratio on each screen will be different. I will not discuss the resolution in depth here, but the primary purpose is to complete the resolution adaptation on the mobile side of the project.

First you need to install lib-flexible:

npm i lib-flexible -S
Copy the code

And introduce it in main.jsx:

import React from 'react'
import ReactDOM from 'react-dom'
import 'lib-flexible/flexible'
import './index.css'
import App from './App'

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>.document.getElementById('root'))Copy the code

Then install postCSS-PxtoREM, which automatically converts your CSS units to REM units after you have written them.

npm i postcss-pxtorem
Copy the code

Create postcss.config.js in the project root directory:

// postcss.config.js
Post.config.js is required to create a project using vite. Postcss.js is deprecated
// You can go to the postCSs-pxtorem repository to see the documentation for the configuration
module.exports = {
  "plugins": [
    require("postcss-pxtorem") ({rootValue: 37.5.propList: [The '*'].selectorBlackList: ['.norem'] // filter out. Norem - classes that start with norem conversion}})]Copy the code

Modify the Index/style. The module. Less:

.index {
  width: 200px;
  height: 200px;
  background: green;
  span {
    color: red; }}Copy the code

Restart the project NPM run dev as follows:

As you can see, 200px has been converted to 5.3333rem and rootValue set to 37.5. You can convert 5.33333 * 37.5 = 200.

The current browser is iPhone 6, and the HTML font size is 37.5px. It is flexible and will change when the phone becomes any other size. Dynamically change the font size of the HTML, so that the corresponding 1rem PX value is always dynamically adapted to change.

When I switched to the iPhone 6 Plus:

It becomes 41.4px, while the div is still 5.33333 REM, so the width of the div is larger, but the screen width of the phone is also larger, which will not affect the visual scale error too much.

Secondary encapsulation of Axios

At this point, it comes to the server-side API of the project. In the previous section, the server-side code was written, but at this point the server project runs on the http://127.0.0.1/7001 port.

At this point you can use http://127.0.0.1/7001 as the baseURL for the project in subsequent requests.

Install NPM I axios-s, create a new utils directory under SRC, and create a new axios.js script:

import axios from "axios";
import { Toast } from "zarm";

const MODE = import.meta.env.MODE // Environment variables

// Set the base path for the request
axios.defaults.baseURL = MODE === 'development' ? '/api' : 'http://127.0.0.1:7001'
axios.defaults.withCredentials = true
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
axios.defaults.headers['Authorization'] = `The ${localStorage.getItem('token') | |null}`
axios.defaults.headers.post['Content-Type'] = 'application/json'

// Configure the POST request, using the request body, which defaults to application/json.
// Interceptors intercept every request
axios.interceptors.response.use(res= > {
    if (typeofres.data ! = ='object') {
        Toast.show('Server exception! ')
        return Promise.reject(res)
    }
    // // Check the request content. If the request content is not 200, an error message is displayed
    if(res.data.code ! = =200) {
        if (res.data.msg) Toast.show(res.data.msg)
        //401 is an unlogged user
        if (res.data.code === 401) {
            window.location.href = '/login'
        }
        / / the return res. Data
        return Promise.reject(res.data)
    }

    return res.data
})

export default axios
Copy the code

Analyze the condition of the above code line by line.

const MODE = import.meta.env.MODE
Copy the code

MODE is an environment variable, which can be obtained from import.meta.env.MODE in a project built using Vite. The environment variable is used to determine whether the current code is running in the development or production environment.

axios.defaults.baseURL = MODE === 'development' ? '/api' : 'http://127.0.0.1:7001'
Copy the code

BaseURL is an AXIOS configuration item that sets the base path of the request, which will be reflected in the actual project. The advantage of configuring the base path is that you can configure it uniformly here when requesting address changes.

axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest' axios.defaults.headers['Authorization'] = `The ${localStorage.getItem('token') | |null}` axios.defaults.headers.post['Content-Type'] = 'application/json'
Copy the code

The above three configurations are for request header Settings. Authorization is used for server authentication. After token is set in the front end, the server verifies the validity of each request by obtaining the token in the request header.

The last line configures the request body to be used for the POST request, which is set to application/ JSON by default.

axios.interceptors.response.use(res= > {
    if (typeofres.data ! = ='object') {
        Toast.show('Server exception! ')
        return Promise.reject(res)
    }
    // // Check the request content. If the request content is not 200, an error message is displayed
    if(res.data.code ! = =200) {
        if (res.data.msg) Toast.show(res.data.msg)
        //401 is an unlogged user
        if (res.data.code === 401) {
            window.location.href = '/login'
        }
        / / the return res. Data
        return Promise.reject(res.data)
    }

    return res.data
})
Copy the code

Interceptors are interceptors. Interceptors intercept every request you make. You can do something about the callback function to return the data. If the value is not 200, an error message will be displayed. If the value is 401, the user has not logged in and jumps to the /login page by default. If it is a normal response, retrun res.data.

Finally, this AXIos is thrown for the page component request.

Create a new index.js file under utils like this:

import axios from './axios'

export const get = axios.get

export const post = axios.post
Copy the code

So when you get it, you write fewer lines of code, you write less code if you can.

7. Proxy configuration

Why does baseURL use/API to request addresses in a development environment? It is actually configured for proxy requests.

After this configuration, when requesting the interface, the request address will look like this:

/api/userInfo
Copy the code

To configure the proxy, open vite.config.js and add the following code:

 server: {
    proxy: {
      '/api': {
        // When the/API path is encountered, it is converted to the value of target
        target: 'http://127.0.0.1:7001'.changeOrigin: true.rewrite: path= > path.replace(/ ^ /api/, ' ') // Rewrite the/API to null}}}Copy the code

After this configuration, development environment, / API/the userInfo – > http://api.chennick.wang/api/userInfo. This solves the age-old cross-domain problem.

But in fact, as long as the server set up a good whitelist, there will be no such cross-domain problems.

Resolve. Alias Alias Settings

The alias has to be set, otherwise you’ll end up with a long list of code like this on the page. /.. /.. /.

Open viet.config. js and add the following configuration:

import path from 'path' export default defineConfig({ ... Resolve: {alias: {'@': path.resolve(__dirname, 'SRC '), // SRC path 'config': Path.resolve (__dirname, 'SRC /config') // SRC path}},})Copy the code

At this point, you can modify the previous code as follows:

router/index.js

import Index from '@/pages/Index'
import About from '@/pages/About'
Copy the code

App.jsx

import routes from '@/router'
Copy the code

9. To summarize

At this point, the basic development environment has been set up, involving building tools, front-end framework, UI component library, HTTP request library, CSS preloader, cross-domain proxy, mobile resolution adaptation, of course, this is the most basic preparation.