1 入手项目
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;}
2 项目分析
不能慌张,我们可是前端工程师...那么我们该怎么办呢?首先我们先分析一下我们可以怎么办,那么我们首先分析一下他使用的技术栈和运用场景。
2.1 运用场景
通过和项目组,产品的沟通。该项目,是运行在微信公众号上的的一个h5页面。那么能够给你的时间,差不多是一周时间,去熟悉了解,整个项目。
2.2 技术栈架构分析
1. js架构使用技术栈
1.1 jquery
1.2 jweixin
1.3 swiper.min
2. css解决方案
纯手写,手动rem
其实这时候,不难发现,就是累加的js,http未封装状态...
方法 | 方案 | 缺点 | 文件夹隔离 | 将老代码,丢到我看不到的地方,继续开发新项目。(看不到,那就当做没有问题) | 在老项目的代码,硬伤还是硬伤,新代码的架构被迫跟随 | 微前端 | 做一个大规模容器,将新老项目做一个中间的桥接,让主架构负责项目的沟通,保证2个服务器正常运行 | 微前端的技术方案,大部分实例是作为后端管理系统中运行,在手机端中的适配能力未知。 | webpack | 多文件打包方案,让新老代码,在工具中兼容 | 人力改代码 |
---|
3 webpack技术
webpack的优点不言而喻,如果不清楚的,可以去看webpack官网的介绍
4 目录结构
先将原来的文件复制出一个来,我们也不希望在改动的过程中,破坏了代码原本的功能
mkdir jq-webpack
yarn add webpack@4.19.1 webpack-cli@2.1.4 -D
touch webpack.config.js
"build": "webpack --mode production --config=webpack.config.js",
"server": "webpack-dev-server --hot --config=webpack.config.js"
在项目结构不算过于复杂的情况下,其实我们还是可以理一下思路,就比如项目中,其实初始化css,js 都是可以抽离出来并且,可以形成一套完整的路由体系。那么就可以制作一个项目抽离的目录结构
- router
- index.js 组合文件
- resource.js 资源文件
- router.js 路由文件
- src
- common 公用的部分
- css
- js
- images
- pages 老项目的对应关系
- index
- index.html
- index.js
- index.css
- activity
- index.html
- index.js
- index.css
- ....
- utils 工具库
index.js
- public 难以做处理文件
- images
- lib
- package.json
- webpack.config.js
4.1 package.json
{
"name": "webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --mode production --config=webpack.config.js", // 打包指令
"server": "webpack-dev-server --hot --config=webpack.config.js", // 启动指令
"upload-test": "NODE_ENV=test node ./deploy", // 自动化上传-测试
"upload-prod": "NODE_ENV=prod node ./deploy" // 自动化上传-正式
},
"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.0",
"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.1.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"
}
}
5 多页面配置
我们使用的技术,是比较普遍的webpack,多页面技术我们可以看到,每一个老项目的html 中,都会引入关于jq、自己的index.js、然后一股脑的images,又或许有些是放在自己的images里面...放在我们开始做一些隔离,分类组合,开始开多个文件夹,放入html、js、css。样式将会比较清楚,这时候开始做一些外部引入的操作。 首先我们配置一下router的文件,我这边做了一些拆分,当然你如果页面能模块化的,建议拆分的更细。
5.1 路由设置
const entry = {
// 首页
"index-css": "./src/index/index.css",
"index-js": "./src/index/index.js",
// 活动页
"activity-css": "./src/pages/activity/index.css",
"activity-js": "./src/pages/activity/index.js",
}
module.exports = {
entry
};
const router = [
{
name: "首页",
filename: "index.html",
chunks: ["index-css", "index-js"], // 如果多个可以引入多个
template: "./src/pages/index/index.html",
},
{
name: "活动",
filename: "activity.html",
chunks: ["activity-css", "activity-js"],
template: "./src/pages/activity/index.html",
},
];
module.exports = {
router
};
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, //打包后的文件名
minify: false,
chunks: item.chunks, //每个html只引入对应的js和css
inject: true,
hash: true, //避免缓存js。
template: item.template
})
);
});
module.exports = {
htmlWebpackPlugins,
entry: resource.entry
};
- 直接使用cdn引入库、这里又分为免费库,和公司自己的库两种
- 放入公共的public中,页面中引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>活动页面</title>
</head>
<body>
<script src="./public/lib/jquery-1.8.0.min.js" charset="utf-8"></script>
</body>
</html>
这里是一段艰苦的历程.....
5.2 webpack.config.js 配置
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"); // 清除dist
const CompressionPlugin = require("compression-webpack-plugin");
const ProgressBarPlugin = require("progress-bar-webpack-plugin");
module.exports = {
devServer: {
contentBase: path.resolve("dist"),
host: "localhost", //服务器的IP地址,这里先使用loaclhost地址
compress: true, //服务端压缩是否开启
port: "8888", //配置服务端口号
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"), //引入cssnano配置压缩选项
cssProcessorOptions: {
discardComments: { removeAll: true }
},
canPrint: true //是否将插件信息打印到控制台
}),
new ExtractTextWebpackPlugin({
filename: "css/[name].[hash:8].css", // 配置提取出来的css名称
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: {
//当加载的图片小于limit时,会将图片编译成base64字符串的形式,
//当图片大于这个limit,会用file-loader进行加载
limit: 10000,
//在webpack4.x必须显式的指定fallback备用方法,这里指定为file-loader
fallback: require.resolve("file-loader"),
encoding: "base64",
outputPath: "images/",
publichPath: "images/",
name: "[name].[hash:8].[ext]",
esModule: false //解决方法
}
}
]
}
]
}
};
6 图片路径问题
在处理这一段代码的时候,最令人无奈的就是关于,jq中插入过html,你所有的语法是$('.xx').html(xx),在这个阶段,你很容易会遇到一个巨大的坑..就是图片无法被webpack去解析,这样打包出来的图片。
- 直接以cdn的形式引入,一个http图片,不存在这个问题
- 把页面放入到我们已经准备好的public目录下,使用绝对路径去解决
- 在代码中使用require方法去引入一些图片,然后作为代码的解析
7 单页面配置-Vue
前面做了那么多业务,目的就是从业务上可以往vue页面靠齐...那么肯定不会是以vue-cil 这样方式出现,那么我就要研究一下vue-cil的本质,其实还是一个webpack,那么为什么可以解析vue,less。既然是多页面了,又怎么兼容?
7.1 vue项目建立
- src
- pages
- vue-template
- index.html
- pages
- 404.vue
- home.vue
- routers
- index.js
- App.vue
7.2 配置单页面
在我们刚刚的路由中,我们设置一下
"vue-template-js": "./src/pages/vue-template/main.js"
{
name: "vue-template",
filename: "template.html",
chunks: ["babel-polyfill", "vue-template-js"],
template: "./src/pages/vue-template/index.html",
}
7.3 webpack配置
首先我们需要加载less,然后将我们熟悉的px,自动转rem、自动加上兼容前缀
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"
}
7.4 配置rem自动化
postcss.config.js
module.exports = {
plugins: {
autoprefixer: {
overrideBrowserslist: ["Android >= 4.0", "iOS >= 7"]
},
"postcss-pxtorem": {
rootValue: 37.5,
propList: ["*"]
}
}
};
7.5 编写vue-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模板</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"
/>
<div class="webpack-home__title">
正在加载资源
</div>
<div class="webpack-home__sub-title">
初次加载资源可能需要较多时间 请耐心等待
</div>
</div>
<div class="webpack-home__footer"></div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</body>
</html>
7.6 编写vue-template/main.js
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");
8 自动化发布
在deploy目录下,设置
/*
*定义多个服务器账号 及 根据 SERVER_ID 导出当前环境服务器账号
*/
const SERVER_LIST = [
{
id: 0,
name: "A-测试环境",
host: "127.0.0.1", // ip
url: "http://www.baidu.com",
port: 22, // 端口
username: "root", // 登录服务器的账号
password: "", // 登录服务器的账号
path: "" // 发布至静态服务器的项目路径
}
];
module.exports = SERVER_LIST;
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(
"正在发布到" +
(process.env.NODE_ENV === "prod" ? "生产" : "测试") +
"服务器..."
);
var Client = require("ssh2").Client;
var conn = new Client();
conn
.on("ready", function() {
// rm 删除dist文件,\n 是换行 换行执行 重启nginx命令 我这里是用docker重启nginx
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) {
// 在执行shell命令后,把开始上传部署项目代码放到这里面
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("发布失败.\n"));
throw err;
} else {
console.log(
chalk.green(
"Success! 成功发布到" +
(process.env.NODE_ENV === "prod" ? "生产" : "测试") +
"服务器! \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,
});
9 git地址
github.com/MYQ1996/jq-…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!