老旧前端项目如何升级工程化的项目

因为历史的原因存在着大量的老旧前端项目,而在今天的开发环境中已经不再适应了,于是产生了升级到新的环境的需求。比如笔者当前的一个登录页面项目,就是以下面为技术栈的老旧项目。

  • 基于 jQuery
  • 包管理基于 require.js,甚至有的没有使用全局变量
  • 没有工程化,只使用 nginx 跑起页面

问题的产生

当前旧工程乃基于 Java 工程下的子前端项目,通过 Java Maven 打包压缩混淆 js/css,如下 Maven 插件的配置。

其实,笔者认为通过 Java 项目整合前端工程,也是一个不错的全栈选择,其特点是前后端虽然各自开发,但在同一工程下,打包部署亦是同时一起进行的,也就是打包部署没有前后端分离,前后端一起打包部署。这一点,是自从 Servlet 3.0 发布之后 JAR 包完全具备整合相关静态资源的能力(以前的 war 包就是一个网站,当然支持静态资源混合,JAR 包则不然)。而且通过 Maven 插件实现前端构建打包,也是一个不错的思路。但通过一系列实践得出的结论是,如果是小型的前端项目,修改不多,则此法甚秒,然则比较大型的前端项目,频繁修改的话,则此法弊端渐显。因为哪怕小小的前端修改,又要跟随后端项目发包部署,时间漫长且心里压力不舒坦。

于是在后来的升级改造中,我们希望可以部署也可以前端分离。

是否改造为 MVVM 架构

jQuery 无疑是以前主流的前端库,如果贸然升级到今天的 vue/react,貌似也没有很大的必要,MVVM 固然很好而且顺手,但升级需要考虑升级后的风险,如果业务代码不通过测试则麻烦很大,抵消了升级后带来的收益。况且,新的 node/npm 工程也完全支持 jQuery 引入,只是配置上稍有不同。总之,最后决定保留 jQuery 旧有的开发模式。

升级到 node/npm 环境

今天主流前端开发离不开 node/npm,于是升级第一件事就是切换此环境。构建工具,显然还是以 webpack 为主。

JS 迁移

Require.js 使用 AMD 语法,Webpack 同样支持 AMD 语法,能够动态分析项目中的依赖项,这是项目迁移成功的关键所在。只不过 Webpack 不是直接支持,而且需要稍微配置一下。

先看一下原项目中的`requirejs.config.js``:

js 复制代码
requirejs.config({
    baseUrl: '/public/js',
    paths: {
        jquery: 'lib/jquery',
    	jqueryUI: 'lib/jquery-ui',
    	moment: 'lib/moment',
    	qs: 'lib/qs',
    	lodash: 'lib/lodash',
    	selectize: 'lib/selectize',
    }
});

require(['jquery', 'moment', 'modal/index'], function( $, moment, modal ){
    console.log($);
});

对 require.js 中的配置内容映射为 webpack 中的 alias,以解决路径解析问题。让 webpack 能够解析上面path中的地址。

开始配置·webpack.config.js·中的resolve.alias

js 复制代码
const path = require('path');
const resolve = filePath => path.resolve(process.cwd(), filePath);

module.exports = {
 resolve: {
    alias: {
        jquery: resolve('lib/jquery'),
    	jqueryUI: resolve('lib/jquery-ui'),
    	moment: resolve('lib/moment'),
    	qs: resolve('lib/qs'),
    	lodash: resolve('lib/lodash'),
    	selectize: resolve('lib/selectize'),
    }
  },
}

这样可以让 webpack 可以正确解析 require 的依赖。同时 require 的也可以引入不是 require 的包。

Inline js

内联 JS 是指在 html 中通过<script>置入的脚本。 这类脚本只能复制到新的一个包中,优先加载。

src js

src JS 是指在 html 中通过<scrip src="xxx.js">置入的脚本。 这类 JS 迁移到新的 JS 包,由 index.js/main.js 导入。

JS 压缩、混淆、source map

Webpack 构建下,打包成品是否压缩的取决于webpack.config.jsmode,设置为production即可压缩。

打开 devtool: 'source-map'生成 source map。

混淆需要 webpack-obfuscator 插件。

参考:

引入 CSS

以前是<link rel="stylesheet" type="text/css" href="css/normalize.css" /> 方式引入 CSS 的,现在不用,改为在 js 包中:

js 复制代码
import '../css/normalize.css';
import '../css/font_login/iconfont.css';

Inline CSS style 不作修改。

图片迁移

Webpack5 新特性:资源模块 ,诸如引入图片的方式可以使用 webpack5 中的资源模块,而 url-loader, file-loader, raw-loader 三个库已经不再维护。

新方式:

json 复制代码
module: {
    rules: [
        // 图片处理
        {
            test: /\.(png|jpg|svg|jpeg|gif)$/i,
            type: "asset/resource",
        },
    ],
},

对于需要转化成 base64 的图片,可以使用type: asset/inline

对于其他资源文件,有需要被 XHR(Ajax)请求的资源,也可以如法炮制,关键是让 Webpack 能够识别是可控的资源,然后require()。例如 jQ 的 i18n 资源。

json 复制代码
module: {
     rules: [
         {// i18n 资源文件
             test: /\.(properties)$/i,
             type: "asset/resource",
         },
     ],
 },

参考:《构建webpack5.x 知识体系:3、基础之图片、html、js、其他配置》手把手带你学webpack(3)-- Webpack中加载图片及其他资源webpack5资源最佳加载方案

JS 里面的图片

例如这种,在 JS 动态引入图片url('image/index/portal_bg.jpg')

通过上面的 asset 配置之后,我们需要使用require()去引入图片地址。

HTML 里面的图片资源

HTML 里面的图片指的是<img src />引入的图片。虽然在 webpack5 中我们使用assets-module资源模块类型(asset module type)来替代比如 raw-loader 、url-loader、file-loader,但 HTML 图片不在assets-module负责之列。这是因为默认情况下,HTML 模板只是纯文本,Webpack 不能理解你想要复制在文本中引用的 asset。

这个时候需要再次增加一个 loader 配置来处理 HTML。添加 html-loader 依赖:

shell 复制代码
npm i html-loader -d

修改webpack.config.js

json 复制代码
    module: {
        rules: [
            { test: /.html$/, loader: 'html-loader' } // 修正 HTML 加载 img src 图片
        ],
    },

然后修改图片位置,注意是相对于 HTML 文件的位置:

关于 base64 图片

base64 后的图片会增加体积。

不要无脑将所有图片都使用 base64 编码处理,我们使用base64编码的主要目的还是为了减少http 请求

对于那些数量多,但是体积小的图片文件,如果以文件的方式打包的话会产生多条 http请求,而如果把它们全都编码成 base64 存在 js 文件中,那 http 请求只会有一次。

图片压缩插件:image-webpack-loader

开发环境服务器

为了能够有一个良好的开发体验,我们需要在代码更新时及时看到更新后的效果,这时候就需要webpack-dev-server的帮助了。

json 复制代码
 devServer: {
     static: {
         directory: path.resolve(__dirname, '../dist'),
     },
     watchFiles: ['public/**/*'],
     compress: true,
     port: 8000,
     open: false, // 是否自动打开浏览器
     hot: true,
 },

hot: true表示开启 HMR 热更新,open则表示运行webpack serve命令后自动启动浏览器打开页面。

proxy 代理配置

旧有的方式是将页面 url 与接口 url 通过本地的 Nginx 配置在同一域(Domian)下面,Nginx 反代接口,接口访问接口。如今在 Webpack 的帮助下,一切都那么自然丝滑,------它整合了一个后台服务,相当于 Ng 角色,就是代理。

json 复制代码
devServer: {
        proxy: [ // 配置代理(只在本地开发有效,上线无效)
             {
                 context: ['/api'],
                 target: 'http://xxxx:8100/aut',
                 changeOrigin: true
             }
         ]
 },

代理接口可能要多试几下,在 Postman 等工具中调通再回到开发环境中试试。

参考:12

相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
浪浪山小白兔6 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
limit for me7 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者7 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
qq_392794488 小时前
前端缓存策略:强缓存与协商缓存深度剖析
前端·缓存