最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • webpack: 多页面+vue单页面 老项目jq升级

    正文概述 掘金(前端泥瓦匠)   2020-12-15   510

    1 入手项目

    webpack: 多页面+vue单页面 老项目jq升级webpack: 多页面+vue单页面 老项目jq升级
    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-…


    起源地下载网 » webpack: 多页面+vue单页面 老项目jq升级

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元