1 start a project
It was an old company, not a big company, but when we downloaded it from Git, we suddenly found that the project had a kind of heartache.
It’s 2020 and someone is using such an old scheme for a project. So at this point, what do we do, we get lost in thought, maintenance? Or are you going to run? Hold on, let’s look at the code…
Directory a common index code…. Not even pulling away… The following code is approximately 1000 + lines….
blockquote,body,dd,dl,dt,fieldset,form,h1,h2,h3,h4,h5,h6,hr,html,iframe,input,legend,li,ol,p,pre,td,textarea,th,ul{padding:0; margin:0} html{-webkit-overflow-scrolling:touch; -webkit-text-size-adjust:100%; font-family:Arial, Helvetica, sans-serif; } body{-webkit-overflow-scrolling:touch; -webkit-box-sizing:border-box; box-sizing:border-box} a,body,select,select:focus,textarea,textarea:focus{-webkit-tap-highlight-color:transparent; outline:0; -webkit-appearance:none} li{list-style-type:none} table{border-collapse:collapse; border-spacing:0}
fieldset{border:none}
legend{display:none}
a:active,a:hover,button{outline:0} input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box; box-sizing:border-box} b,em,i{font-style:normal; font-weight:400} a{text-decoration:none; -webkit-tap-highlight-color:transparent} @media screen and (min-width:1440px){html{font-size:200%}}
@media screen and (max-width:1440px){html{font-size:200%}}
@media screen and (max-width:1024px){html{font-size:150%}}
@media screen and (max-width:980px){html{font-size:150%}}
@media screen and (max-width:750px){html{font-size:150%}}
@media screen and (max-width:720px){html{font-size:150%}}
@media screen and (max-width:640px){html{font-size:150%}}
@media screen and (max-width:540px){html{font-size:150%}}
@media screen and (max-width:480px){html{font-size:125%}}
@media screen and (max-width:432px){html{font-size:120%}}
@media screen and (max-width:414px){html{font-size:115%}}
@media screen and (max-width:400px){html{font-size:112.5%}}
@media screen and (max-width:393px){html{font-size:104%}}
@media screen and (max-width:375px){html{font-size:104%}}
@media screen and (max-width:360px){html{font-size:100%}}
@media screen and (max-width:320px){html{font-size:87.5%}}
@media screen and (max-width:240px){html{font-size:75%}} body{background-color: #f7f7f7; } .popBox,.popBind,.popBind_text,.popBind_error{position: fixed; width:100%; height:100%; background:rgba(0.0.0.0.5); color:#999999; display: none; top:0px; z-index:10; } .popBoxCont{width:18.1875rem; background-color: #fff; border-radius:0.3125rem; position: absolute; left:50%; top:50%; transform:translate(-50%, -50%); padding-bottom:2.0313rem; } .popBox_top{font-size:1rem; line-height:1.2rem; margin-top:2.75rem; margin-bottom:1.1875rem; } .popBox_top i{font-size:1.3125rem; line-height:1.5rem; vertical-align:bottom; margin-left:0.4375rem; color:#5bba48; font-weight:bold; } .popBoxDetail p{margin-left:2.375rem; margin-right:2.375rem; } .popBoxDetail .popBox_counseName{font-size:1rem; line-height:1.3125rem; color:#5bbb47; background-color: #edfbea; margin-bottom:1.6563rem; position: relative; margin-left:1.9688rem; margin-right:1.9688rem; padding:0.2375rem 0.4688rem; }Copy the code
2 Project Analysis
Don’t panic, we’re front-end engineers… So what do we do? So let’s first look at what we can do, so let’s first look at the technology stack he uses and the scenarios he uses.
2.1 Application Scenarios
Through communication with the project team and the product. This project is an H5 page running on the wechat public account. So that gives you time, about a week, to familiarize yourself with the project.
2.2 Analysis of technology stack architecture
1. Js architecture using technology stack 1.1 jquery 1.2 Jweixin 1.3 swiper.min 2. CSS solution pure handwriting, manual REMCopy the code
In fact, at this time, it is not difficult to find, is the accumulation of JS, HTTP unencapsulated state...Copy the code
methods | plan | disadvantages |
---|---|---|
Folder isolation | Put the old code where I can’t see it, and work on the new project. (If you can’t see it, consider it no problem) | In old project code, hard or hard, the architecture of new code is forced to follow |
Micro front-end | Make a large-scale container, make a bridge between the old and new projects, let the main architecture take charge of project communication, and ensure the normal operation of the two servers | Most of the technical solutions of the micro front end are run in the back-end management system, and the adaptability of the mobile end is unknown. |
webpack | Multi-file packaging solution, so that old and new code, compatible in the tool | Manual code modification |
3 webpack technology
The advantages of Webpack are self-evident, if not clear, you can go to the webpack official website
In essence, Webpack is a static module bundler for modern JavaScript applications. When WebPack works with an application, it recursively builds a dependency Graph containing every module the application needs, and then packages all of those modules into one or more bundles.
4 Directory Structure
First of all, we certainly don’t want to change the old project code, after all, it is an old project… You changed it… In case the east and west walls collapse.. The final accident was not a small one. What about the new page.. We definitely want to use single-page technology, after all, loading and experience, after all, have a good experience.
Let’s make a copy of the original file. We don’t want to break the original function of the code in the process of making changes
Mkdir jq-webpack YARN add [email protected] [email protected] -d touch webpack.config.jsCopy the code
At this point, the project needs to add directives to package.json
"build": "webpack --mode production --config=webpack.config.js"."server": "webpack-dev-server --hot --config=webpack.config.js"
Copy the code
We can configure webpack.config.js in principle, we can configure multiple environments, but we will configure one for simplicity
In the case of the project structure is not too complex, in fact, we can still clarify the idea, such as the project, in fact, the initialization of CSS, JS can be removed and can form a complete set of routing system. Then you can make a directory structure for items to pull out
- router-index. js combination file - resource-. js Resource file - router-. js Route file - src-common Common part - CSS-js-images-pages Mapping between old items - index - index.html - index.js - index.css - activity - index.html - index.js - index.css - .... -utils library index.js -public Difficult to do with file - images-lib-package. json -webpack.config.jsCopy the code
4.1 package. Json
{
"name": "webpack"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
"build": "webpack --mode production --config=webpack.config.js".// Package instruction
"server": "webpack-dev-server --hot --config=webpack.config.js".// Start command
"upload-test": "NODE_ENV=test node ./deploy".// Automatic upload - test
"upload-prod": "NODE_ENV=prod node ./deploy" // Automatic upload - official
},
"keywords": []."author": ""."license": "ISC"."devDependencies": {
"autoprefixer": "^ 9.1.0"."babel-plugin-import": "^ 1.13.3"."chalk": "^ 4.1.0." "."clean-webpack-plugin": "^ 3.0.0"."compression-webpack-plugin": "^ 6.0.0"."copy-webpack-plugin": "^ 4.6.0"."css-loader": "^ 3.3.0"."cssnano": "^ 4.1.10"."expose-loader": "1.0.3"."extract-text-webpack-plugin": "^ 4.0.0 - beta."."file-loader": "^ 6.2.0"."html-webpack-plugin": "4.5.0"."html-withimg-loader": "^ 0.1.16"."less": "^ 3.13.0"."less-loader": "^ 4.1.0." "."mini-css-extract-plugin": "^ 1.3.2." "."optimize-css-assets-webpack-plugin": "^ 5.0.0"."ora": "^ 5.1.0"."post-loader": "^ 2.0.0." "."postcss-loader": "^ 2.1.1"."postcss-pxtorem": "^ 5.0.0"."postcss-safe-parser": "^ 5.0.2"."progress-bar-webpack-plugin": "^ 2.1.0." "."scp2": "^ 0.5.0"."style-loader": "^ 1.0.0"."url-loader": "^ 4.4.1"."vue-loader": "^ 15.9.5"."vue-template-compiler": "^ 2.6.12." "."webpack": "4.19.1"."webpack-cleanup-plugin": "0.5.1"."webpack-cli": "^ 2.1.4." "."webpack-dev-server": "3.11.0"
},
"dependencies": {
"babel-polyfill": "^ 6.26.0"."lib-flexible": "^" 0.3.2."vant": "^ 2.11.2"}}Copy the code
5 Multi-page configuration
The technique we use is the popular Webpack, multi-page technique. We can see that in the HTML of every old project, we would introduce jQ, our own index.js, and then a bunch of images, maybe some of them in our own images… We started doing some isolation, sorting groups, starting to open multiple folders, putting HTML, JS, CSS. The style will be clear, and it’s time to start doing some external introductions. First of all, let’s configure the router file. I have done some splitting here. Of course, if you can modularize the page, I suggest splitting it more finely.
5.1 Route Settings
Resource-.js puts the Settings in the file path into the resource management library
const entry = {
/ / home page
"index-css": "./src/index/index.css"."index-js": "./src/index/index.js"./ / activity page
"activity-css": "./src/pages/activity/index.css"."activity-js": "./src/pages/activity/index.js",}module.exports = {
entry
};
Copy the code
Router.js is ungrouped in the routing page
const router = [
{
name: "Home page".filename: "index.html".chunks: ["index-css"."index-js"].// If more than one can introduce more than one
template: "./src/pages/index/index.html"}, {name: "Activity".filename: "activity.html".chunks: ["activity-css"."activity-js"].template: "./src/pages/activity/index.html",},];module.exports = {
router
};
Copy the code
index.js
const htmlPlugin = require("html-webpack-plugin");
const resource = require("./resource");
const routerObj = require("./router");
const htmlWebpackPlugins = [];
routerObj.router.forEach(item= > {
htmlWebpackPlugins.push(
new htmlPlugin({
filename: item.filename, // The packaged file name
minify: false.chunks: item.chunks, // Only the corresponding JS and CSS are imported for each HTML
inject: true.hash: true.// Avoid caching js.
template: item.template
})
);
});
module.exports = {
htmlWebpackPlugins,
entry: resource.entry
};
Copy the code
There are two ways to do this
- Direct use of CDN into the library, here is divided into free library, and the company’s own library two kinds
- Put it in the public public, introduced in the page
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Activities page</title>
</head>
<body>
<script src=". / public/lib/jquery - 1.8.0 comes with. Min. Js. "" charset="utf-8"></script>
</body>
</html>
Copy the code
It’s been a rough ride here…..
5.2 webpack. Config. Js configuration
const path = require("path");
const HtmlRouter = require("./router/index");
const CopyPlugin = require("copy-webpack-plugin");
const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin");
const optimizeCss = require("optimize-css-assets-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); / / remove dist
const CompressionPlugin = require("compression-webpack-plugin");
const ProgressBarPlugin = require("progress-bar-webpack-plugin");
module.exports = {
devServer: {
contentBase: path.resolve("dist"),
host: "localhost".// The server IP address, using the loaclhost address
compress: true.// Whether server compression is enabled
port: "8888".// Configure the service port number
stats: "errors-only",
historyApiFallback: true,
overlay: true
},
entry: HtmlRouter.entry,
output: {
path: path.resolve("dist"),
filename: "js/[name].[hash:8].js"
},
plugins: [
new ProgressBarPlugin(),
new CleanWebpackPlugin(),
new optimizeCss({
cssProcessor: require("cssnano"), // Introduce the CSsnano configuration compression option
cssProcessorOptions: {
discardComments: { removeAll: true }
},
canPrint: true // Whether to print the plug-in information to the console
}),
new ExtractTextWebpackPlugin({
filename: "css/[name].[hash:8].css".// Set the extracted CSS name
allChunks: true
}),
new CopyPlugin(
[
{
from: path.resolve(__dirname, "./src/public/lib"),
to: path.resolve(__dirname, "./dist/public/lib")
},
{
from: path.resolve(__dirname, "./src/public/images"),
to: path.resolve(__dirname, "./dist/public/images")
}
],
{ ignore: [], copyUnmodified: true }
),
new CompressionPlugin()
].concat(HtmlRouter.htmlWebpackPlugins),
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
"~": path.resolve(__dirname, "src/pages/vue-template")
}
},
module: {
rules: [
{
test: /\.(htm|html)$/i,
loader: "html-withimg-loader"
},
{
test: /\.css$/,
use: ExtractTextWebpackPlugin.extract({
fallback: "style-loader",
use: [
{
loader: "css-loader"
}
],
publicPath: ".. /"
})
},
{
test: /\.(png|jpg|gif|jpeg|svg)$/i,
use: [
{
loader: "url-loader",
options: {
// When the loaded image is less than limit, the image will be compiled as a base64 string,
// When the image is larger than this limit, file-loader is used to load the image
limit: 10000.// The fallback alternative method must be explicitly specified in webpack4.x, which is file-loader
fallback: require.resolve("file-loader"),
encoding: "base64",
outputPath: "images/",
publichPath: "images/",
name: "[name].[hash:8].[ext]",
esModule: false // The solution}}]}};Copy the code
6. Picture path problem
One of the most frustrating aspects of dealing with this code is that jQ inserts HTML, and all your syntax is $(‘.xx’).html(xx). At this stage, you can easily run into a huge pit… Is the image can not be resolved by Webpack, so packaged out of the image.
There are three solutions
- There is no problem with importing an HTTP image directly as a CDN
- Put the page in the public directory we have prepared, and use the absolute path to solve the problem
- Use the require method in the code to introduce some images, which are then parsed as code
7 Single-page configuration -Vue
The purpose of doing so much business in front is to rely on the VUE page from the business… It’s not going to be vue-cil, so I’m going to look at the nature of vue-cil. It’s actually a Webpack, so why can I parse vUE, less? Since it is multi-page, how compatible?
7.1 VUE project establishment
The familiar project format is back, so I won’t cover it here
- src
- pages
- vue-template
- index.html
- pages
- 404.vue
- home.vue
- routers
- index.js
- App.vue
Copy the code
7.2 Configuration Page
In the route we just did, let’s set it up
Js added to the resource file
"vue-template-js": "./src/pages/vue-template/main.js"
Copy the code
Added to router.js routing file
{
name: "vue-template".filename: "template.html".chunks: ["babel-polyfill"."vue-template-js"].template: "./src/pages/vue-template/index.html",}Copy the code
7.3 webpack configuration
First we need to load less, then we are familiar with the PX, automatically to REM, automatically with the compatible prefix
const VueLoaderPlugin = require("vue-loader/lib/plugin");
plugins: [
...
new VueLoaderPlugin()
]
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
"~": path.resolve(__dirname, "src/pages/vue-template"),
vue$: "vue/dist/vue.esm.js"}},module: {
rules: [{test: /\.css$/,
use: ExtractTextWebpackPlugin.extract({
fallback: "style-loader".use: [{loader: "css-loader"}, {loader: "postcss-loader"],},publicPath: ".. /",}, {})test: /\.less$/,
use: ExtractTextWebpackPlugin.extract({
use: [{loader: "css-loader"}, {loader: "postcss-loader"}, {loader: "less-loader"],},fallback: "style-loader",}, {})test: /\.vue$/,
loader: "vue-loader",}]},externals: {
vue: "Vue"."vue-router": "VueRouter"
}
Copy the code
7.4 Configuring REM Automation
postcss.config.js
module.exports = {
plugins: {
autoprefixer: {
overrideBrowserslist: ["Android > = 4.0"."iOS >= 7"]},"postcss-pxtorem": {
rootValue: 37.5.propList: ["*"]}}};Copy the code
7.5 writing vue – the template/HTML
<! DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="Width =device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/>
<title>Vue template</title>
</head>
<style>
html.body.#app {
height: 100%;
margin: 0;
padding: 0;
}
.webpack-home {
background-color: # 303133;
height: 100%;
display: flex;
flex-direction: column;
}
.webpack-home__main {
user-select: none;
width: 100%;
flex-grow: 1;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.webpack-home__footer {
width: 100%;
flex-grow: 0;
text-align: center;
padding: 1em 0;
}
.webpack-home__footer > a {
font-size: 12px;
color: #ababab;
text-decoration: none;
}
.webpack-home__loading {
height: 32px;
width: 32px;
margin-bottom: 20px;
}
.webpack-home__title {
color: #fff;
font-size: 14px;
margin-bottom: 10px;
}
.webpack-home__sub-title {
color: #ababab;
font-size: 12px;
}
.ql-editor {
min-height: 150px;
}
.ql-snow .ql-picker {
height: 36px ! important;
}
@media only screen and (-webkit-min-device-pixel-ratio: 3),
only screen and (min--moz-device-pixel-ratio: 3),
only screen and (-o-min-device-pixel-ratio: 3/1),
only screen and (min-device-pixel-ratio: 3),
only screen and (min-resolution: 458dpi),
only screen and (min-resolution: 3dppx) {
.van-tabbar--fixed {
padding-bottom: 15px ! important; }}</style>
<body>
<div id="app">
<div class="webpack-home">
<div class="webpack-home__main">
<img
class="webpack-home__loading"
src="./svg/loading-spin.svg"
alt="loading"
/>
<div class="webpack-home__title">Loading resources</div>
<div class="webpack-home__sub-title">It may take a long time to load resources for the first time</div>
</div>
<div class="webpack-home__footer"></div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</body>
</html>
Copy the code
7.6 writing vue – the template/main. Js
Instantiate a VUE project, doing a simple instantiation configuration and adding routes
More can be configured according to the business situation, such as what to load on demand, here is just a simple elaboration of the structure
import routers from "./routers/index";
import App from "~/App.vue";
import Vant from "vant";
import "vant/lib/index.css";
import "lib-flexible";
Vue.use(VueRouter);
Vue.use(Vant);
const router = new VueRouter({
routes: routers
});
new Vue({
router,
render: h= > h(App)
}).$mount("#app");
Copy the code
8 Automatic Publishing
In the deploy directory, set
Products.js server configuration
/* * Define multiple server accounts and export the current environment server account */ based on the SERVER_ID
const SERVER_LIST = [
{
id: 0.name: "A- Test Environment".host: "127.0.0.1".// ip
url: "http://www.baidu.com".port: 22./ / port
username: "root".// Account for logging in to the server
password: "".// Account for logging in to the server
path: "" // Publish the project path to the static server}];module.exports = SERVER_LIST;
Copy the code
Index.js executes the function
const scpClient = require("scp2");
const ora = require("ora");
const chalk = require("chalk");
const servers = require("./products");
let server = servers[process.env.NODE_ENV === "prod" ? 1 : 0];
const spinner = ora(
"Posting to" +
(process.env.NODE_ENV === "prod" ? "Production" : "Test") +
"Server..."
);
var Client = require("ssh2").Client;
var conn = new Client();
conn
.on("ready".function() {
// rm delete dist file, \n is newline, execute restart nginx command
let dels = `rm -rf ${server.path}\n mkdir ${server.path}`;
conn.exec(dels, function(err, stream) {
if (err) throw err;
stream
.on("close".function(code, signal) {
// After executing shell command, put the start upload deployment project code in this
spinner.start();
scpClient.scp(
"dist/",
{
host: server.host,
port: server.port,
username: server.username,
password: server.password,
path: server.path,
},
function(err) {
spinner.stop();
if (err) {
console.log(chalk.red("Publishing failed.\n"));
throw err;
} else {
console.log(
chalk.green(
"Success! Successfully published to" +
(process.env.NODE_ENV === "prod" ? "Production" : "Test") +
"Server! \n"));console.log(server.url); }}); conn.end(); }) .on("data".function(data) {
console.log("STDOUT: " + data);
})
.stderr.on("data".function(data) {
console.log("STDERR: " + data);
});
});
})
.connect({
host: server.host,
port: server.port,
username: server.username,
password: server.password,
});
Copy the code
9 git address
Github.com/MYQ1996/jq-…