Vue3 TSX Mobile Terminal Project based on Vue Cli4 (I)
Project introduction
It’s been nearly a year since Vue3 was released in preview. In my own trials, the underlying rendering mechanism was optimized better than React Hooks without considering specific optimizations. So it’s time to start experimenting with Vue3.
Since I felt that the Vue Cli4 was mature enough, there was no need to build Webpack from scratch, it would be much more efficient to re-pack it. Therefore, this paper constructs Vue3 framework based on Vue Cli4, mainly including:
- Distinguish between multiple environment configurations
- Mobile debugging tool Eruda
- eslint
- stylelint
- Px2vw mobile terminal adaptive
- HardSource development build acceleration
- Babel-plugin-import is introduced on demand
- Static resource upload CDN in production environment
- Express start
- Commonly used Hooks encapsulation
- Vue3 TSX common syntax
For this project, I recommend developing everything using the Component API to make better use of the Hooks capabilities. At the same time, in order to improve Vue2
can not be code prompts, etc., the official advocate using VUE template syntax for development, but template is not as flexible as TSX. So you can still use TSX for development in situations that require high flexibility. Template is still recommended for everyday business code development, for reasons explained in Chapter 4. With the Component API, the TSX writing of Vue will not be as awkward as the JSX writing of Vue2 before, and the TSX and Vue files can be seamlessly connected, and you can choose according to the business form and custom.
To avoid being too long, I will divide it into four chapters. This article focuses on project creation, differentiating multi-environment configurations, and integrating eruda mobile debugging tools.
Create a project
First we create the base project with Vue Cli4:
Project creation
vue create yuor-template
We then chose Manually Select Features to customize some of the basic configuration we needed
Vue CLI v4.5.4 ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ │ New version available 4.5.4 - > 4.5.12 │ │ Run NPM I - g @vue/cli to update! │ │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘? Please pick a preset: Default ([Vue 2] Babel, esLint) Default (Vue 3 Preview) ([Vue 3] Babel, eslint) ❯ Manually select featuresCopy the code
Select desired features
Here we check vUE version selection, Babel, TypeScript, Router, Vuex, CSS preprocessing, Lint
? Check the features needed for your project: ◉ Choose Vue version ◉ Babel ◉ TypeScript infection Progressive Web App (PWA) Support ◉ Router port Vuex CSS pre-processors microblog Linter/Formatter Unit Testing was borne out of infection into E2E TestingCopy the code
Select the Vue version
Since our project is based on Vue3, the version selected here is Vue3
? Choose a version of Vue.js that you want to start the project with
2.x
❯ 3.x (Preview)
Copy the code
Other options
Because there are more choices here, it is not a waste of space, the configuration is as follows:
Set not to use class component writing, to use Babel for escape, to use history mode for the router, to use dart-Sass style preprocessors, to use ESLint + Standard Config, to do Lint detection when saving, and to place individual component configurations in individual component configuration files
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with 3.x (Preview)
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N)
Copy the code
Trying to run project
Once the installation is complete, we can go to the new project for a trial run
🎉 Successfully created project vue-plus-example.
👉 Get started with the following commands:
$ cd vue-plus-example
$ npm run serve
Copy the code
Distinguish between multiple environment configurations
In the previous step, we created the basic project framework with Vue Cli4. Generally, during actual development, there are local development environment, development environment, test environment, pre-release environment staging environment and production environment. In view of these different situations, we need a different set of configurations to distinguish the configurations such as Bucket for CDN uploading, API address, domain name for jumping to other sites, etc. So let’s configure a multi-environment configuration.
Add an environment configuration file
Json, development.json, test.json, staging. Json, production.json.
Here’s an overview of what each file does:
- Index.js: method class to get configuration files, which encapsulates a series of operations to read configuration based on the current environment variables
- Local. Json: the configuration of local development environment, singled out the advantage of this file is want to go to when we in the local development in different environment of the debug interface and so on, you just need to copy content from other environment configuration file cover, and avoid direct modify the configuration files of the other environment, may lead to problems after release.
- Development. json: Configuration of the development environment
- Test. json: configuration of the test environment
- Staging. Json: configuration of the pre-publishing environment
- Production. json: configuration of the production environment
Writing configuration files
The configuration file format here is only a set of structure defined by myself at present, and you can define your own structure according to your own needs. I take the structure of Development. json as an example in the following code, and change the corresponding configuration value for the rest of the environment according to the actual configuration of your own project
// development.json
{
// Build time configuration
"buildtime": {
// Local service IP address and port configuration
"origin_server": {
"ip": "127.0.0.1"."port": "5000"
},
// CDN configuration. This value needs to be filled in according to the CDN configuration of your project
// This configuration will be used in the subsequent static resource upload CDN. If static resource upload CDN is not used, this configuration can be omitted
"cdn": {
"region": "oss-cn-shenzhen"."accessKeyId": "xxxxxxxxxxxx"."accessKeySecret": "xxxxxxxxxx"."bucket": "frontend".// create a bucket to store static files
"path": "vue-plus/development/".// Here I use the format of the project name (vue-plus) + environment variable as the path
"cdnPath": "https://frontend.oss-cn-shenzhen.aliyuncs.com/vue-plus/development/" // CDN path after upload, used for publicPath}},// Run time configuration
"runtime": {
// Identifies the current environment
"env": "development".// Public API address
"api": "https://dev-api.wynneit.cn".// API address of the account
"account": "https://dev-account-api.wynneit.cn".// host is the configuration item in the project that jumps to another site
"host": {
// Mobile site domain name
"mobile": "https://dev-mobile.wynneit.cn"
},
// Wechat configuration
"wechat": {
// Wechat APPID
"appId": "wxf8xxxxxxxxxxxa53a"}}}Copy the code
Write configuration read methods
Since the project was ultimately deployed using Docker and Jenkins, I use a custom environment parameter front_env, passed in from Jenkins configuration.
// index.js
const fs = require("fs");
const path = require("path");
const lodash = require("lodash");
const cfgDir = path.join(__dirname);
const env = process.env.front_env;
function generateCfg() {
// Default configuration path
const defaultConfigPath = path.join(cfgDir, "development.json");
// Local configuration path
const localConfigPath = path.join(cfgDir, "local.json");
let localConfig = {};
let envConfig = {};
if (fs.existsSync(localConfigPath)) {
localConfig = require(localConfigPath);
}
/ / to get
if (env) {
const envCfgPath = path.join(cfgDir, `${env}.json`);
if (fs.existsSync(envCfgPath)) {
envConfig = require(envCfgPath);
} else {
console.warn(
`\nConfiguration file specified by env var ${env} = ${envCfgPath} does not exist.\n`); }}// Get the default configuration
const defaultConfig = require(defaultConfigPath);
// Splice the final configuration
const mixedConfig = lodash.merge({}, defaultConfig, localConfig, envConfig);
return mixedConfig;
}
module.exports = generateCfg;
Copy the code
Mount the config configuration
Here I have mounted the environment configuration to the Window object, so that we can easily see some of the current environment configuration in Chrome DevTool, convenient for some troubleshooting.
-
Add config slot in /public/index.html
<! DOCTYPEhtml> <html lang="zh-CN"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="Width =device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" /> <link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <title><%= htmlWebpackPlugin.options.title %></title> <! -- Add custom configuration --> <%= htmlWebpackPlugin.options.config %> </head> <body> <noscript> <strong >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript> <div id="app"></div> <! -- built files will be auto injected --> </body> </html> Copy the code
-
Create vue.config.js, set the value of config slot, and set devServer
// Get the environment configuration const cfg = require("./config/index") ();module.exports = { devServer: { host: config.buildtime.origin_server.ip, port: config.buildtime.origin_server.port, }, chainWebpack: (config) = > { // HTML template injection configuration config.plugin("html").tap((args) = > { // Environment configuration script const configScript = ` <! --configArea--><script>window.CUSTOMCONFIG =The ${JSON.stringify(cfg.runtime)}</script><! --endOfConfigArea-->`; args[0].config = configScript; returnargs; }); }};Copy the code
-
Once the configuration is complete, run the project and type window.CUSTOMCONFIG into Chrome DevTool to see the configuration of our current environment.
Write the config declaration file
We have successfully mounted the config configuration to window.CUSTOMCONFIG, but because we use TypeScript in our project, we want to use it without error and with the correct code prompt. So we also need to write a declaration file for window.customConfig.
-
Create the window.d.ts file in the project directory SRC /typings/global.
Here I use typings as the unified folder for declaration files, and global as the folder for globally related declaration files.
-
Write the window.d.ts file
interface CustomConfig { // Runtime environment variables env: "local" | "development" | "test" | "staging" | "production"; // Public interface address api: string; // Interface address of the account account:string; // Jump to another platform domain name host: Record<string.string>; // Wechat configuration wechat: { appId: string,}}interface Window { CUSTOMCONFIG: CustomConfig; } Copy the code
-
Try importing it in main.ts so that we can prompt the code that CUSTOMCONFIG already exists under window. (reboot if vscode is not prompted).
Eruda mobile debugging tool
Since the positioning of this project is on the mobile terminal, I will choose to embed tools such as vConsole or Eruda in the non-production environment during the development of the mobile terminal, so that we can view logs and quickly locate problems during the debugging of the real machine. Because Eruda is more powerful, I chose to embed Eruda here.
Adding Html slots
Still is in the public/index. The HTML to add custom configuration items < % = htmlWebpackPlugin. Options. Eruda % >
<! DOCTYPEhtml>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="Width =device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title>
<! -- Custom configuration -->
<%= htmlWebpackPlugin.options.config %>
<! -- Eruda configuration -->
<%= htmlWebpackPlugin.options.eruda %>
</head>
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div>
<! -- built files will be auto injected -->
</body>
</html>
Copy the code
Add erUDA slot content
Add the eruda configuration to the chainWebpack file in vue.config.js, where CDN is used directly, because this package is only used as a development debugging tool, so there is no need to NPM install into the project. This also prevents erUDA from being packaged into the project to increase the package size of the project.
// Get the environment configuration
const cfg = require("./config/index") ();module.exports = {
devServer: {
host: cfg.buildtime.origin_server.ip,
port: cfg.buildtime.origin_server.port,
},
chainWebpack: (config) = > {
// HTML template injection configuration
config.plugin("html").tap((args) = > {
// Embed environment configuration script
const configScript = ` <! --configArea--><script>window.CUSTOMCONFIG =The ${JSON.stringify(config.runtime)}</script><! --endOfConfigArea-->`;
args[0].config = configScript;
// Inject erUDA in non-local development environment and non-production environment
if(! ["local"."production"].includes(cfg.runtime.env)) {
const erudaCDN = "/ / cdn.bootcdn.net/ajax/libs/eruda/2.4.1/eruda.min.js";
const erudaDomCDN = "/ / cdn.jsdelivr.net/npm/[email protected]";
const erudaScript = ` <! --erudaArea--> <script src="${erudaCDN}"></script>
<script src="${erudaDomCDN}"></script> <script> eruda.init({ tool: ['console', 'network', 'elements', 'resources', 'snippets', 'sources'], }); eruda.add(erudaDom); </script> <! --endOfRrudaArea-->`;
args[0].eruda = erudaScript;
}
returnargs; }); }};Copy the code
Eruda test
Eruda is not required for Chrome DevTool, so I have excluded the local environment. Json to test whether eruda is installed properly. After finishing the modification, run the project again. We can see that the icon of Eruda has appeared in the lower right corner.