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