webpack是一个现代JavaScript应用程序的静态模块打包器。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundle。javascript
(function (root, factory) { if (typeof exports === 'object') { module.exports = factory(); //commonjs环境下能拿到返回值 } else if (typeof define === 'function' ) { define(factory); //define(function(){return 'a'}) AMD } else { window.eventUtil = factory(); } })(this, function() { // module return { //具体模块代码 addEvent: function(el, type, handle) { //... }, removeEvent: function(el, type, handle) { }, }; });
npm install webpack@3.12.0 -D
css
// 整个程序的入口文件 import Vue from './vue.js' import App from './App.js' // 模块总体加载 // import {num,num2,add} from './App.js' // console.log(num); // console.log(num2); // add(3,5); // import * as object from './App.js' // console.log(object); // console.log(object.num); // console.log(object.num2); // add(3,5); new Vue({ el:'#app', components:{ App }, template:`<App />` });
var App = { template:` <div> 我是一个入口组件 </div> ` }; //1. 声明并导出 export var num = 2; //做为一整个对象key导出 //2. 声明再导出 var num2 = 4; export {num2}; //3.抛出一个函数 export function add(x,y) { return console.log(x+y); } //4.抛出一个对象 export default App;
{ "name": "29_module", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "build": "webpack ./main.js ./build.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^3.12.0" } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"></div> <script type="text/javascript" src="./build.js"></script> </body> </html>
关于setimmediate介绍连接:html
http://www.ruanyifeng.com/blog/2014/10/event-loop.html前端
修改配置文件名为:webpack.dev.config.js和webpack.prod.config.jsvue
"scripts": { "dev": "webpack --config ./webpack.dev.config.js", "prod": "webpack --config ./webpack.prod.config.js" }
import './main.css'
对于webpack来讲,css文件也是一个模块,可是像这样的文件,webpack得须要loaders去处理这些文件java
npm i css-loader style-loader -D
node
module:{ loaders:[ { // 遇到后缀为.css的文件,webpack先用css-loader加载器去解析这个文件 // 最后计算完的css,将会使用style-loader生成一个内容为最终解析完的css代码的style标签,放到head标签里。 // webpack在打包过程当中,遇到后缀为css的文件,就会使用style-loader和css-loader去加载这个文件。 test:/\.css$/, loader:'style-loader!css-loader' } ] }
import imgSrc from './myGirl.jpg' export default{ template:` <div> <img :src="imgSrc" alt="" /> </div> `, data(){ return { imgSrc:imgSrc } } };
对文件的处理,webpack得须要url-loader
和file-loader
jquery
npm i url-loader file-loader -D
webpack
module:{ loaders:[ { test:/\.css$/, loader:'style-loader!css-loader' }, { test:/\.(jpg|png|jpeg|gif|svg)$/, loader:'url-loader?limit=4000' } ] },
webpack最终会将各个模块打包成一个文件,所以咱们样式中的url路径是相对入口html页面的,而不是相对于原始css文件所在的路径的。这就会致使图片引入失败。这个问题是用file-loader解决的,file-loader能够解析项目中的url引入(不只限于css),根据咱们的配置,将图片拷贝到相应的路径,再根据咱们的配置,修改打包后文件引用路径,使之指向正确的文件。 简易,对于比较小的图片,使用base64编码,能够减小一次图片的网络请求;那么对于比较大的图片,使用base64就不适合了,编码会和html混在一块儿,一方面可读性差,另外一方面加大了html页面的大小,反而加大了下载页面的大小,得不偿失了呢,所以设置一个合理的limit是很是有必要的。
npm i html-webpack-plugin --save-dev
git
const path = require('path'); //2.导入模块 const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // 入口 entry:{ // 能够有多个入口,也能够有一个,若是一个,就默认从这一个入口开始分析 "main" : './src/main.js' }, output:{ // 指定产出的目录 path: path.resolve('./dist'), //相对转绝对 filename:'build.js' }, // 声明模块 // 包含各个loader module:{ loaders:[ { // 遇到后缀为.css的文件,webpack先用css-loader加载器去解析这个文件 // 最后计算完的css,将会使用style-loader生成一个内容为最终解析完的css代码的style标签,放到head标签里。 // webpack在打包过程当中,遇到后缀为css的文件,就会使用style-loader和css-loader去加载这个文件。 test:/\.css$/, loader:'style-loader!css-loader' }, { test:/\.(jpg|png|jpeg|gif|svg)$/, loader:'url-loader?limit=100000' }, { test:/\.less$/, loader:'style-loader!css-loader!less-loader' } ] }, watch:true, //文件监视改动 自动产生build.js //添加插件 plugins:[ new HtmlWebpackPlugin({ //插件的执行运行与元素索引有关 templat:'./src/index.html', //参照物 }) ] }
CommonsChunkPlugin主要是用来提取第三方库和公共模块,避免首屏加载的bundle文件或者按需加载的bundle文件体积过大,从而致使加载时间过长,着实是优化的一把利器.
src目录下各个文件内容,尽可能保持简单,让你们理解:
--common.js export const common = 'common file'; --main1.js import {common} from './common.js' import Vue from 'vue' console.log(Vue,`main1 ${common}`); --main2.js import {common} from './common.js' import Vue from 'vue' console.log(Vue,`main1 ${common}`)
webpack.config.js
const path = require('path'); module.exports = { // 入口 entry:{ // 能够有多个入口,也能够有一个,若是有一个就默认从这一个入口开始分析 "main1":'./src/main1.js', "main2":'./src/main2.js' }, output:{ path:path.resolve('./dist'),//相对转绝对 filename:'[name].js' }, watch:true,//文件监视改动 自动产出build.js }
执行命令npm run build,
问题:查看main1.js和main2.js,会发现共同引用的common.js文件和vue都被打包进去了,这确定不合理,公共模块重复打包,体积过大。
修改webpack.config.js新增一个入口文件vendor和CommonsChunkPlugin插件进行公共模块的提取:
const path = require('path'); const webpack = require('webpack'); const packagejson = require('./package.json'); module.exports = { // 入口 entry: { "main1": './src/main1.js', "main2": './src/main2.js', "vendor": Object.keys(packagejson.dependencies) //获取生产环境依赖的库 }, //出口 output: { path: path.resolve('./dist'), //相对转绝对 filename: '[name].js' }, watch: true, //文件监视改动 自动产出build.js plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['vendor'], filename: '[name].js' }) ] }
查看dist目录,新增了一个vendor.js的文件
打包信息:
经过查看vendor.js文件,发现main1.js和main2.js文件中依赖的vue和common.js都被打包进vendor.js中,同时还有webpack的运行文件。总的来讲,咱们初步的目的达到,提取公共模块,可是它们都在同一个文件中。
到这里,确定有人但愿自家的vendor.js纯白无瑕,只包含第三方库,不包含自定义的公共模块和webpack运行文件,又或者但愿包含第三方库和公共模块,不包含webpack运行文件。
其实,这种想法是对,特别是分离出webpack运行文件,由于每次打包webpack运行文件都会变,若是你不分离出webpack运行文件,每次打包生成vendor.js对应的哈希值都会变化,致使vendor.js改变,但实际上你的第三方库实际上是没有变,然而浏览器会认为你原来缓存的vendor.js就失效,要从新去服务器中获取,其实只是webpack运行文件变化而已,就要人家从新加载,好冤啊~
这里咱们分两步走:
(1)抽离webpack的运行文件
修改webpack配置文件
plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['vendor', 'runtime'], filename: '[name].js', })
其实上面这段代码,等价于下面这段:
plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: '[name].js' }), new webpack.optimize.CommonsChunkPlugin({ name: 'runtime', filename: '[name].js', chunks: ['vendor'] }), ]
上面两段抽离webpack运行文件代码的意思是建立一个名为runtime的commons chunk进行webpack运行文件的抽离,其中source chunks是vendor.js。
查看dist目录下,新增了一个runtime.js的文件,其实就是webpack的运行文件
再来查看一下命令行中webpack的打包信息,你会发现vendor.js的体积已经减少,说明已经把webpack运行文件提取出来了:
但是,vendor.js中还有自定义的公共模块common.js,人家只想vendor.js拥有项目依赖的第三方库而已(这里是jquery),这个时候把minChunks这个属性引进来。
minChunks能够设置为数字、函数和Infinity,默认值是2,并非官方文档说的入口文件的数量,下面解释下minChunks含义:
(2) 抽离第三方库和自定义公共模块
minChunks设为Infinity,修改webpack配置文件以下
plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['vendor','runtime'], filename: '[name].js', minChunks: Infinity }), new webpack.optimize.CommonsChunkPlugin({ name: 'common', filename: '[name].js', chunks: ['main1','main2']//从first.js和second.js中抽取commons chunk }), ]
查看dist目录下,新增了一个common.js的文件:
再来查看一下命令行中webpack的打包信息,自定义的公共模块分离出来:
这时候的vendor.js就纯白无瑕,只包含第三方库文件,common.js就是自定义的公共模块,runtime.js就是webpack的运行文件。
webpack ensure 有人称它为异步加载,也有人说作代码切割。其实说白了,它就是把js模块给独立导出一个.js文件的,而后使用这个 模块的时候,webpack会构造script dom元素,由浏览器发起异步请求这个js文件。
webpack.ensure的原理:
它就是 把一些js模块给独立出一个个js文件,而后须要用到的时候,在建立一个script对象,加入 到document.head对象中便可,浏览器会自动帮咱们发起请求,去请求这个js文件,在写个回调,去 定义获得这个js文件后,须要作什么业务逻辑操做。
main.js依赖三个js
针对上面的需求,优化方案
假设 A.js B.js vue.js都是很是大的文件 由于 A.js B.js 都不是main.js必须有的,即将来可能发生的操做,那么咱们把 他们利用异步加载,当发生的时候再去加载就好了
vue.js.js是main.js当即立刻依赖的工具箱。可是它又很是的大,因此将其配置打包成一个公共模块, 利用浏览器的并发加载,加快下载速度。ok,构思完成,开始实现。
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"></div> <button id="aBtn">Abtn</button> <br> <button id="bBtn">Bbtn</button> </body> </html>
定义了两个button
而后看看 main.js
import Vue from 'vue' console.log(Vue); document.getElementById('aBtn').onclick = function(){ require.ensure(['./B.js'],function(){ var A = require('./A.js'); alert(A.data); //异步里面再导入同步模块--实际是使用同步中的模块 var Vue1 = require('vue'); }) } document.getElementById('bBtn').onclick = function(){ require.ensure([],function(){ var B = require('./B.js'); alert(B.data); }) }
能够看到,A.js, B.js 都是点击后才ensure进来的。何时加载完成呢? 就是 require.ensure() 第二个函数参数,即回调函数,它表示当下载js完成后,发生的。
webpack打包后,造成
1.npm install webpack-dev-server --save-dev
经常使用配置参数
--open 自动打开浏览器
--hot 热更新 ,不在刷新的状况下替换 css样式
--inline 自动刷新
--port 9999 指定端口
--process 显示编译进度
npm run dev
babel-core
:
javascript babel-core的做用是把js代码分析成ast(抽象语法树),方便各个插件分析语法进行相应的处理。有些新语法在低版本 js 中是不存在的,如箭头函数,rest 参数,函数默认值等,这种语言层面的不兼容只能经过将代码转为 ast,分析其语法后再转为低版本 js
abel转译器自己,提供了babel的转译API,如babel.transform等,用于对代码进行转译。像webpack的babel-loader就是调用这些API来完成转译过程的。
babel-loader
:
在将es6的代码transform进行转义,就是经过babel-loader来完成
babel-preset-env
若是要自行配置转译过程当中使用的各种插件,那太痛苦了,因此babel官方帮咱们作了一些预设的插件集,称之为preset,这样咱们只须要使用对应的preset就能够了。以JS标准为例,babel提供了以下的一些preset:
babel-plugin-transform-runtime
Babel 默认只转换新的 JavaScript 语法,而不转换新的 API。例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(好比 Object.assign)都不会转译。若是想使用这些新的对象和方法,必须使用 babel-polyfill,为当前环境提供一个垫片。
参考连接:https://segmentfault.com/q/1010000005596587?from=singlemessage&isappinstalled=1 看这个回答,说的很是详细。
npm install babel-core babel-loader babel-preset-env babel-plugin-transform-runtime -D
loader:[ { // 处理es6,7,8 test:/\.js$/, loader:'babel-loader', options:{ presets:['env'],//处理关键字 plugins:['transform-runtime'],//处理函数 } } ]
配置完成以后执行 npm run dev
发现!!!!!
解决:
排除不包含node_modules的路径,而后再配置文件中修改
loader:[ { // 处理es6,7,8 test:/\.js$/, loader:'babel-loader', exclude:/node_modules/, options:{ presets:['env'],//处理关键字 plugins:['transform-runtime'],//处理函数 } } ]
也会发现,当排除掉node_modules文件中的es6代码编译后,编译的时间也快了
之前出错的,3601毫秒的时候就开始出错了。。。。
排除掉node_modules以后
npm install vue-loader@14.1.1 vue-template-compiler@2.5.17 -D
//组件的模板结构 <template> <div> {{ text }} </div> </template> //组件的业务逻辑 <script> export default { data(){ return { text:'hello Single file' } } } </script> //组件的样式 <style> body{ background-color: green; } </style>
import Vue from 'vue'; import App from './App' new Vue({ el:'#app', //Render函数是Vue2.x版本新增的一个函数; // 使用虚拟dom来渲染节点提高性能,由于它是基于JavaScript计算。 // 经过使用createElement(h)来建立dom节点。createElement是render的核心方法。其Vue编译的时候会把template里面的节点解析成虚拟dom; render:c=>c(App) // components:{ // App // }, // template:`<App />` });
// 处理Vue文件 { test:/\.vue$/, loader:'vue-loader' }
参考连接:https://github.com/vuejs/vue-cli/tree/v2#vue-cli--
安装:
npm install -g vue-cli
用法:
$ vue init < template-name > < project-name >
例:
$ vue init webpack my-project
目前可用的模块包括:
vue-cli3x的官方文档:https://cli.vuejs.org/
Vue-cli3 中vue.config.js文件配置参考文档:https://cli.vuejs.org/zh/config/#integrity
// vue.config.js 配置说明 //官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions // 这里只列一部分,具体配置参考文档 module.exports = { // 部署生产环境和开发环境下的URL。 // 默认状况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 //例如 https://www.my-app.com/。若是应用被部署在一个子路径上,你就须要用这个选项指定这个子路径。例如,若是你的应用被部署在 https://www.my-app.com/my-app/,则设置 baseUrl 为 /my-app/。 baseUrl: process.env.NODE_ENV === "production" ? "./" : "/", // outputDir: 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致) outputDir: "dist", //用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包以后,静态资源会放在这个文件夹下) assetsDir: "assets", //指定生成的 index.html 的输出路径 (打包以后,改变系统默认的index.html的文件名) // indexPath: "myIndex.html", //默认状况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存。你能够经过将这个选项设为 false 来关闭文件名哈希。(false的时候就是让原来的文件名不改变) filenameHashing: false, // lintOnSave:{ type:Boolean default:true } 问你是否使用eslint lintOnSave: true, //若是你想要在生产构建时禁用 eslint-loader,你能够用以下配置 // lintOnSave: process.env.NODE_ENV !== 'production', //是否使用包含运行时编译器的 Vue 构建版本。设置为 true 后你就能够在 Vue 组件中使用 template 选项了,可是这会让你的应用额外增长 10kb 左右。(默认false) // runtimeCompiler: false, /** * 若是你不须要生产环境的 source map,能够将其设置为 false 以加速生产环境构建。 * 打包以后发现map文件过大,项目文件体积很大,设置为false就能够不输出map文件 * map文件的做用在于:项目打包后,代码都是通过压缩加密的,若是运行时报错,输出的错误信息没法准确得知是哪里的代码报错。 * 有了map就能够像未加密的代码同样,准确的输出是哪一行哪一列有错。 * */ productionSourceMap: false, // 它支持webPack-dev-server的全部选项 devServer: { host: "localhost", port: 1111, // 端口号 https: false, // https:{type:Boolean} open: true, //配置自动启动浏览器 // proxy: 'http://localhost:4000' // 配置跨域处理,只有一个代理 // 配置多个代理 proxy: { "/api": { target: "<url>", ws: true, changeOrigin: true }, "/foo": { target: "<other_url>" } } } };
先后端分离:
后端提供接口(api)
前端写页面 ajax技术
40张表 增删改查 4接口
http://127.0.0.1:8080/user
http://127.0.0.1:8080/add_user
http://127.0.0.1:8080/delete_user
http://127.0.0.1:8080/update_user
(1)分工明确,提升效率 ,兼容问题
一种软件的架构风格,设计风格,而不是标准,为客户端和服务端的交互提供一组设计原则和约束条件。
每一个URL表明一种资源,URL中尽可能不要用动词,要用名词,每每名词跟数据库表格相对应。
通常来讲,数据库中的表都是同种记录的集合,全部API中的名词也应该使用复数。
举例来讲,有一个API提供动物园(zoo)的信息,还包括各类动物和雇员的信息,则它的路径应该设计成下
面这样。
https://api.example.com/v1/zoos https://api.example.com/v1/animals https://api.example.com/v1/employees
对于资源的具体操做类型,由HTTP动词表示
经常使用的HTTP动词有下面五个(括号里对应的sql命令)
GET(SELECT):从服务器取出资源(一项或多项)。 POST(CREATE):在服务器新建一个资源。 PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。 PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。 DELETE(DELETE):从服务器删除资源。
https://v1.bootcss.com/
https://www.bootcss.com/api/mycss
https://api.bootcss.com/mycss
若是记录数量不少,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。
?limit=10:指定返回记录的数量 ?offset=10:指定返回记录的开始位置。 ?page=2&per_page=100:指定第几页,以及每页的记录数。 ?sortby=name&order=asc:指定返回结果按照哪一个属性排序,以及排序顺序。 ?animal_type_id=1:指定筛选条件
select post,count(1) from user where id > 20 group by post having avg(age) > 25 order by age desc limit 0,3;
https://www.bootcss.com/v1/mycss
1** 信息,服务器收到请求,须要请求者继续执行操做
2** 成功,操做被成功接收并处理
3** 重定向,须要进一步的操做以完成请求
4** 客户端错误,请求包含语法错误或没法完成请求
5** 服务器错误,服务器在处理请求的过程当中发生了错误
GET请求 返回查到全部或单条数据
POST请求 返回新增的数据
PUT请求 返回更新数据
PATCH请求 局部更新 返回更新整条数据
DELETE请求 返回值为空
若是状态码是4xx,就应该向用户返回出错信息。通常来讲,返回的信息中将error做为键名,出错信息做为键值便可。
{ error: "Invalid API key" }
若是遇到须要跳转的状况 携带调转接口的URL
Hypermedi API的设计,好比github的API就是这种设计,访问api.github.com会获得一个全部可用的API的网址列表。
{ "current_user_url": "https://api.github.com/user", "authorizations_url": "https://api.github.com/authorizations", // ... }
从上面能够看到,若是想获取当前用户的信息,应该去访问 api.github.com/user,就会获得下面的记过
{ message: "Requires authentication", documentation_url: "https://developer.github.com/v3/users/#get-the-authenticated-user" }
(1)API的身份认证应该使用OAuth 2.0框架
(2)服务器返回的数据格式,应该尽可能使用JSON,避免使用XML