0.简介
现在的开发都是讲究的是前后端的分离,但是有时候一些传统的老项目用的技术十分的不顺手,接下来讲一讲我是如何把Vue框架集成到老项目中去的
1.项目环境配置:
- 后端:SSH
- 前端:npm,webpack vue全家桶
首先来一个整个项目的截图
传统项目的结构图想必大家对这个结构已经十分的了解了,这里简单的介绍下这个目录的结构:
- .settings,.classpath,.project都是Eclipse里面的配置问你件
- adf , res ,core,metedata 是关联的其他项目的源码
- metedata是代码生成器
- src 是以SSH为框架的后台代码
- WebRoot是前端代码
吐:下,这个就是老旧的JavaWeb项目,adf ,core,等都是引入的外部的的项目,这些东西是特喵的本可以打成jar包的!
2.理清楚思路:
来来来,先整理一下这个思路
在整个项目中,我们最关心的问题就是这个开发的流程怎么走,首先,明确一下开发的流程:我这里采取从前到后的方式:即由一串url说起:如 http://127.0.0.1:8080/satellite_image//index/index.jsp ,这个是指向的是index.jsp,即index.jsp是整个页面的入口,index.jsp主要的功用是分为两个部分,1是通过域对象向jsp页面里面进行传值,而作为整个页面的容器,即承载html,那么此时的html和部署在ngix上的纯前端页面就没有什么区别了,我们只需要把npm相关配置文件丢在WebRoot的根目录下即可,说白了,就是整个把整个纯前端应用限制在了WebRoot这么个文件夹下
前端需要分离的部分只能放到WebRoot下进行开发,开发的流程与传统的开发流程也没有实质性的区别:即是这样的,我们所有的jsp都要引入一个关键的*.js文件,作为整个文件的操作入口文件,然后再根据这个文件的模块,利用js模块化的思想和Vue模块化的思想将整个页面进行分隔,
先上个图:
重点关注的前端里面的东西
build文件夹是存放编译之后的js文件,css是指样式文件,images是放置图片的,js是老旧项目原始的文件,懒得管了,js-es6才是我们的重头戏,重点编写的文件,其中api是用来搞数据操作交互的和其他操作,里面封装的Data.js就是重点通过ajax与服务器端的数据进行交互的,然后还有一些地图处理的api啊之类的,components是放置的Vue组件了,啊这些就是前端需要搞的知识点儿了,啊这里的就不详细介绍了,,我们重点关注的是流程的走通对不对,
3.正文:
其实吧,最重点的还是特喵的npm那一堆配置文件
,在实际开发的时候,在npm下就跑到Webroot目录下,跑npm run dev 即可以进行热重载的开发,用npm run build-product进行最终文件的压缩,混淆之类的.
下面针对这些文件进行简单的介绍一下,先从npm的命令说起:
看一下package.json这么文件,他是整个前端项目的核心组件和文件(复制过去记得把注释去掉):
{
"name": "mzb", //项目的名称
"version": "0.1.0",//版本号
"private": true, //私有项目?
"dependencies": { //项目中实打实需要用到的第三方插件,框架之类的,这些东西说白了,是项目的文件,或者是入口js文件需要用的,需要用的,会编译进去代码的
"babel-runtime": "^6.26.0",//运行时,垫片库,貌似没有用到,它的作用是,配合通过babel-plugin-transform-runtime自动重写你的promise等原型对象。但是它不会模拟内置对象原型上的方法,比如Array-prototype.find,
"es5-shim": "^4.5.10",//解决ie8以下的问题,这里投机了,由于入口文件都是import 而这个库只能用require,所以我编译了两次(*/ω\*),在编译完第一次之后,自动注入require('shim/eshim')然后再编译一次
"sweetalert2": "^7.8.4",//甜美的弹出框
"vue": "^2.5.13",//
"vuex": "^3.0.1" //
},
"scripts": { // 输入 npm run 脚本时,所能执行的命令结合,在执行脚本的时候是可以指定一些参数的,相当于cmd中进行执行命令,多个命令之间用 && 进行分隔
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack",//执行webpack的命令
"server": "webpack-dev-server --open",
"dev": "webpack-dev-server --devtool eval-source-map --progress --colors --hot --inline ", //执行热更新开发者模式
"build": "webpack --config ./webpack.config.js --progress",
"build-product": "Set NODE_ENV=production && webpack --config ./webpack.production.config.js --progress && npm run build-product-compatible-ie ",
"build-product-compatible-ie": "webpack --config ./[webpack.compatible-ie.config.js](http://webpack.compatible-ie.config.js/) --progress"
},
"devDependencies": {//这些都是插件,说白了,是编译器需要用到的,是webpack.js需要用到的
"babel-cli": "^6.26.0",//没用到
"babel-core": "^6.26.0",//貌似和babel-profill有关,待研究
"babel-loader": "^7.1.2",//必须要有的转码器啦
"babel-plugin-transform-runtime": "^6.23.0",//配合上述的进行工作滴
"babel-polyfill": "^6.26.0", //用于解决低版本浏览器api不全的问题,加入之后可以为所欲为的使用高级的api,在文件的头部统一使用 import 'babel-polyfill'
"babel-preset-es2015": "^6.24.1",//转成es5的语法 配合bable-loader
"babel-preset-es2015-loose": "^8.0.0",//es5语法的loose模式 配合bable-loader
"babel-preset-latest": "^6.24.1",//当前阶段最新的语法 配合bable-loader
"babel-preset-stage-3": "^6.24.1",//当前的语法 配合bable-loader
"babel-register": "^6.26.0",//待研究,貌似没用到
"babelify": "^7.3.0",//待研究,貌似没用到
"compression-webpack-plugin": "^1.1.3",//gzip压缩插件
"css-loader": "^0.28.7",//编译css文件的
"es3ify-loader": "^0.2.0",//解决ie8-,主要是将访问方式统一抓变成object['prop']的形式
"eslint-loader": "^1.9.0",//代码检查工具
"style-loader": "^0.18.2",//编译样式文件和css-laoder配合,待研究
"vue-loader": "^13.3.0",//编译*.vue组件的
"vue-style-loader": "^3.0.1",//配合vue-laoder
"vue-template-compiler": "^2.5.2",//配合vue-laoder
"webpack": "^3.6.0",//打包工具啦
"webpack-dev-server": "^1.14.1"//热更新用到的服务器啦
}
}
详解开发模式下的webpack.config.js,即 执行npm run dev ,或者npm run build都发生了什么事情
看文件.babelre
{
"presets": [["es2015",{"loose":false}],["stage-3"]], //指定转码时,代码所需要识别的高级语法有哪些
"plugins": [ //转码插件
"transform-runtime",//待研究
"transform-es2015-classes"]//转es6里面的class语法,(其实吧,我觉得只用第一个就可以了,待研究)
}
看文件webpack.js
//这里用到的就是nodejs里面的内容和语法了,遵循CommonJS的规范
const path = require('path')
const webpack = require('webpack'); //使用webpack自带的插件
module.exports = {
devtool: 'eval-source-map', //调试时使用的source map 方便快速查找文件
entry: [
"webpack-dev-server/client?[http://localhost:3000](http://localhost:3000/)",
"webpack/hot/only-dev-server",
__dirname + '/index/js-es6/index.js'
], //入口文件 【注意:__dirname 是node.js中的一个全局变量,它指向当前执行脚本所在的目录,故多用于构建工具的脚本中】
output: {
path: __dirname + '/index/build', //输出的路径
filename: 'index.js' //输出的文件名
// publicPath: '[http://localhost:3000/](http://localhost:3000/)'
},
module: { //多个依赖模块,如babel,react,laod等模块
rules: [ //定义loader的规则,表示如何处理指定格式的拓展文件
{
test: /(\.js|\.jsx)$/,//解析的后缀
use: {
loader: 'babel-loader'//解码器
},
exclude: /node_modules/ //自定哪些文件不搞
},
{
test: /(\.css)$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: { modules: true }
}
]
},
{
test: /(\.vue)$/,
use: [
{ loader: 'vue-loader' }
]
}
]
},
resolve: { alias: { 'vue': 'vue/dist/vue.js' } },//这个是使用完整版,而不只是运行时的vue
plugins: [new webpack.HotModuleReplacementPlugin()], //热加载插件
devServer: {//这个就6了,这个是保证能在tomcat下,即同一个域下,实现热加载,在执行代理时,为保证符合代理的预期效果,可以到tomcat下把需要代理的文件删掉,目前也就只能代理的是这么个入口文件
port: 3000, //代理服务器的端口
proxy: {
'**': {
target: '[http://localhost:8080](http://localhost:8080/)', //代理的 服务器地址,
secure: false,
prependPath: false
}
},
publicPath: '[http://localhost:3000/satellite_image/index/build/](http://localhost:3000/satellite_image/index/build/)',//代理的入口文件的地址,详细的路径呀
historyApiFallback: true
}
}
看文件webpack-inject-js-plugin.js
/*
在编译之后的脚本之后,往其头部添加一些引入的库
用途:多用于连续打包,在下一次打包之前,引入必要的js库
Author zgy
*/
"use strict";
const ConcatSource = require("webpack-sources").ConcatSource;
const ModuleFilenameHelpers = require("./node_modules/webpack/lib/ModuleFilenameHelpers");
const injectScript = (str) => {
if (!str.includes("\n")) return `${str} \n`;
return `${str.split("\n").join("\n ")}\n`;
};
class InjectScript {
constructor(options) {
if (arguments.length > 1)
throw new Error("脚本注入插件只能传入一个参数");
if (typeof options.banner === "object") {
options.banner = options.banner.map(item => `require('${item}');`).join('\n');
}
console.log(options.banner);
if (typeof options === "string")
options = {
banner: `require('${options}')`
};
this.options = options || {};
this.banner = this.options.raw ? options.banner : injectScript(options.banner);
console.log(this.banner);
}
apply(compiler) {
const options = this.options;
const banner = this.banner;
console.log("apply-->"+banner);
compiler.plugin("compilation", (compilation) => {
compilation.plugin("optimize-chunk-assets", (chunks, callback) => {
chunks.forEach((chunk) => {
if (options.entryOnly && !chunk.isInitial()) return;
chunk.files
.filter(ModuleFilenameHelpers.matchObject.bind(undefined, options))
.forEach((file) => {
let basename;
let query = "";
let filename = file;
const hash = compilation.hash;
const querySplit = filename.indexOf("?");
if (querySplit >= 0) {
query = filename.substr(querySplit);
filename = filename.substr(0, querySplit);
}
if (filename.indexOf("/") < 0) {
basename = filename;
} else {
basename = filename.substr(filename.lastIndexOf("/") + 1);
}
const comment = compilation.getPath(banner, {
hash,
chunk,
filename,
basename,
query,
});
console.log("apply-->comment-->"+comment);
console.log("apply-->file-->"+compilation.assets[file]);
return compilation.assets[file] = new ConcatSource(comment, "\n", compilation.assets[file]);
});
});
callback();
});
});
}
}
module.exports = InjectScript;
看文件npm run build-product 发生了什么,重头戏,webpack.compatible-ie.config.js和webpack.production.config.js
看文件webpack.production.config.js
// webpack.production.config.js
const webpack = require('webpack');
const InjectScript = require('./webpack-inject-js-plugin.js');
module.exports = {
entry: [
__dirname + '/index/js-es6/index.js'
], //入口文件 【注意:__dirname 是node.js中的一个全局变量,它指向当前执行脚本所在的目录,故多用于构建工具的脚本中】
output: {
path: __dirname + '/index/build', //输出的路径
filename: 'index.js' //输出的文件名
},
module: {
rules: [{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
},
// {
// test: /(\.js)$/,
// use: {
// loader: 'es3ify-loader',
// }
// },
{
test: /(\.vue)$/,
use: [
{ loader: 'vue-loader' }
]
}
]
},
plugins: [
// new webpack.optimize.OccurrenceOrderPlugin(),
/*
*目前需要解决的是ie中的Object.defineProperty,根据[http://www.aliued.com/?p=3240](http://www.aliued.com/?p=3240) ,暂用得解决方案是转码再转码
*即先webpack转码一次通用的.js文件,然后注入脚本require('es5-shim')等包,再进行另外一次webpack进行打包转码
*/
// new InjectScript({banner:['es5-shim','es5-shim/es5-sham']}),//处理es9以下的浏览器api问题,兼容ie9暂时不用
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({ //混淆插件,其实如果不去兼容ie的即使用 InjectScript注入插件,则可以直接和下面这个文件的内容进行合并
compress: {
properties: false,
warnings: false
},
output: {
beautify: true,
quote_keys: true
},
mangle: {
screw_ie8: false
},
sourceMap: false
})
///配置在了Comatible-ie-config.js里面了
// new CompressionWebpackPlugin({ //gzip 压缩
// asset: '[path].gz[query]',
// algorithm: 'gzip',
// test: new RegExp(
// '\\.(js|css)$' //压缩 js 与 css
// ),
// threshold: 10240,
// minRatio: 0.8
// })
],
resolve: { alias: { 'vue': 'vue/dist/vue.min.js' } }
};
webpack.compatible-ie.config.js,其实如不要使用注入引入的插件,则不要这样子搞,合并即可
//其实这个文件才是最后执行的,哈!
// webpack.production.config.js
const webpack = require('webpack');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
module.exports = {
entry: [
__dirname + '/index/build/index.js'
], //入口文件 【注意:__dirname 是node.js中的一个全局变量,它指向当前执行脚本所在的目录,故多用于构建工具的脚本中】
output: {
path: __dirname + '/index/build', //输出的路径
filename: 'index.js' //输出的文件名
},
module: {
rules: [
{
test: /(\.js)$/,
use: {
loader: 'es3ify-loader',
}
}
]
},
plugins: [
new webpack.BannerPlugin('版权所有,翻版必究'),
// new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
properties: false,
warnings: false
},
output: {
beautify: false,
quote_keys: true
},
mangle: {
screw_ie8: false
},
sourceMap: false
}),
///配置在了Comatible-ie-config.js里面了
new CompressionWebpackPlugin({ //gzip 压缩
asset: '[path].gz[query]',
algorithm: 'gzip',
filename(oldFileName){
// 符合公司框架的解析规则
return oldFileName.substring(0,oldFileName.indexOf("."))+".gzjs";
},
test: new RegExp(
'\\.(js|css)$' //压缩 js 与 css
),
threshold: 10240,
minRatio: 0.8
})
]
};
综上所述,以上的开发流程是这样子的
- 首先新建传统的javaeb项目,maven也可以啦
- 在WebRoot下部署node环境,即编写上述的那些个包之类的,是实际的项目发布时,是不需要/node_moudle/这个文件夹的
- 建立入口html或者jsp
- 新建入口.js,记得抽出一个文件单独处理与服务器的数据交互工作
- 在html中引入这个编译之后的入口文件,入口引入的方式不同,热加载的方式也不同,即webServer中,publicPath需要变一变
- 编写webpack的配置文件,指定入口出口文件啊,配置webserver等
- 在实际部署时,一定要记得跑product.config,让js文件该压缩的压缩,该混淆的混淆
其实上面的那些不看也可以!
第一步:把这些npm相关的文件丢到webroot目录下
第二步:配置好jsp里面的入口*.js
第三步,修改webpack.config里面的入口出口参数,
第四步:到WebRoot目录下:执行npm run dev,部署的时候执行npm run build-product
网友评论