WebPack 是什么
官方就一句話,打包所有的資源。
從阮神的 15 DEOM入手 Webpack
Github 地址
按照 ReadME 操作
- npm webpack-dev-server ,為了能夠運(yùn)行起來demo的代碼
- cd 到任何一個(gè)demo下,執(zhí)行npm run dev 即可運(yùn)行demo
npm run dev 是在 demo下的package.json文件中 配置的 script,實(shí)際上是在執(zhí)行 webpack-dev-server --open
對(duì)DEMO拆解
準(zhǔn)備工作:
- 請(qǐng)保證電腦上有npm
- 創(chuàng)建一個(gè)文件夾 webpack-tutorial
- cmd cd到上面的文件夾,鍵入 npm init 根據(jù)提示步驟創(chuàng)建package.json文件,可以一直enter
- npm install webpack webpack-cli webpack-dev-server 安裝需要的包
-
demo1 :?jiǎn)蝹€(gè)入口
- 創(chuàng)建 webpack.config.js文件,代碼如下
module.exports = { entry: './main.js',//入口文件是當(dāng)前目錄下的 main.js文件 output: { filename: 'bundle.js'//打包后的文件名稱是 bundle.js //這里webpack會(huì)自動(dòng)創(chuàng)建dist文件夾,將bundle.js放到里面。 //這里的./會(huì)指定到 dist下 //比如 filename:'./js/bundle.js' 會(huì)在dist下找js文件夾放入bundle.js文件 //可以通過path指定不同的目錄 } };- 創(chuàng)建 main.js文件 ,代碼如下:
// main.js document.write('<h1>Hello World</h1>');//往頁面上寫hello world- CMD中鍵入 webpack進(jìn)行打包,鍵入進(jìn)行開啟
//webpack 輸出 Asset Size Chunks Chunk Names bundle.js 968 bytes 0 [emitted] main Entrypoint main = bundle.jswebpack-dev-server --open //打開瀏覽器后發(fā)現(xiàn)是一個(gè)ftp的頁面 //我們下面將自動(dòng)創(chuàng)建index.html文件- CMD 鍵入
npm install html-webpack-plugin //安裝自動(dòng)生成html插件- 重新編輯 webpack.config.js
var HtmlwebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './main.js',//入口文件是當(dāng)前目錄下的 main.js文件 output: { filename: 'bundle.js'//打包后的文件名稱是 bundle.js //這里webpack會(huì)自動(dòng)創(chuàng)建dist文件夾,將bundle.js放到里面。 //這里的./會(huì)指定到 dist下 //比如 filename:'./js/bundle.js' 會(huì)在dist下找js文件夾放入bundle.js文件 //可以通過path指定不同的目錄 }, //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), ] };- 重新CMD 鍵入 webpack 打包 ,鍵入 webpack-dev-server --open 開啟server
//webpack輸出 Asset Size Chunks Chunk Names bundle.js 968 bytes 0 [emitted] main index.html 187 bytes [emitted] Entrypoint main = bundle.js會(huì)發(fā)現(xiàn) dist 文件夾下自動(dòng)生成了 index.html并且引入 打包好的 bundle.js文件,瀏覽器正常顯示一個(gè)h1的hello world
-
demo2 :兩個(gè)入口
- 更改 webpack.config.js 文件如下:
var HtmlwebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { bundle1: './main1.js',//入口1 main1.js bundle2: './main2.js'//入口2 main2.js }, output: { filename: '[name].js'//name是entry的鍵名,最后會(huì)生成bundle1.js bundle2.js }, //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), ] };- 分別創(chuàng)建 main1.js 與main2.js
// main1.js document.write('<h1>Hello World</h1>'); // main2.js document.write('<h2>Hello Webpack</h2>');- CMD 鍵入 webpack 打包 ,鍵入 webpack-dev-server --open 開啟server
//webpack 輸出 Asset Size Chunks Chunk Names bundle1.js 968 bytes 0 [emitted] bundle1 bundle2.js 971 bytes 1 [emitted] bundle2 index.html 245 bytes [emitted] Entrypoint bundle1 = bundle1.js Entrypoint bundle2 = bundle2.js [0] ./main1.js 39 bytes {0} [built] [1] ./main2.js 41 bytes {1} [built]會(huì)在dist下 創(chuàng)建 bundle1.js/bundle2.js/index.html,瀏覽器會(huì)有h1的helloworld h2的hellowebpack
demo3 :Babel-loader 的使用
什么loaders:就是webpack使用loaders來預(yù)處理文件,允許打包除了js文件外任何靜態(tài)資源。
什么是Babel-loader:是javascript編譯器,將現(xiàn)行的javascript代碼變成瀏覽器可以兼容的代碼。
-
- 例子中是 react 所有我們先安裝下相關(guān)的包
npm install react react-dom//js 用到 npm install babel-loader babel-core babel-preset-es2015 babel-preset-react //這里說明一下 babel-loader單獨(dú)安裝一下7.1.5的版本,因?yàn)樽钚碌?版本 打包時(shí)會(huì)報(bào)錯(cuò)- 創(chuàng)建main.jsx文件
// main.jsx //我們需要增加一部分代碼 //增加一個(gè)創(chuàng)建wrapper div的過程 //這邊我的index.html是自動(dòng)創(chuàng)建的,打包后在更改 會(huì)報(bào)錯(cuò) //不知道阮神是怎么弄的,等我研究明白了再回來說明一下 //如下方法可成功顯示 var div = document.createElement('div'); div.id = 'wrapper'; document.body.appendChild(div); //結(jié)束 const React = require('react'); const ReactDOM = require('react-dom'); ReactDOM.render( <h1>Hello, world!</h1>, document.querySelector('#wrapper')//將h1這個(gè)標(biāo)簽放到 id是wrapper的div中 );- 修改webpack.config.js文件
var HtmlwebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './main.jsx',//不說明了 output: { filename: 'bundle.js' }, //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), ], module: { rules: [ { test: /\.jsx?$/,//匹配.jsx文件 exclude: /node_modules/,//不包含這個(gè)文件夾 npm包 use: { loader: 'babel-loader',//使用babel-loader這個(gè) options: { presets: ['es2015', 'react']//使用 es2015 跟react //這里說明一下,這里的順序是從右到左加載的,即,先用react再用es2015 } } } ] } };- CMD 鍵入 webpack 打包 ,鍵入 webpack-dev-server --open 開啟server
//webpack 輸出 Asset Size Chunks Chunk Names bundle.js 248 KiB 0 [emitted] [big] main index.html 187 bytes [emitted]
demo4 :css-loader使用
-
- cmd 鍵入
npm install css-loader style-loader -
- 創(chuàng)建 app.css文件
body { background-color: blue; }- 更改 webpack.config.js,增加一個(gè)css-loader
var HtmlwebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), ], module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ 'style-loader', 'css-loader' ]//同樣的 從右到左加載 }, ] } };- 更改main.js文件
require('./app.css');- CMD 鍵入 webpack 打包 ,鍵入 webpack-dev-server --open 開啟server
//webpack 輸出 Asset Size Chunks Chunk Names bundle.js 147 KiB 0 [emitted] main index.html 187 bytes [emitted] demo5 :image loader
不做贅述,需要 npm url-loader。與上一個(gè)demo類似
- demo6 : CSS Module
Css Module:給CSS加入了局部作用域和模塊依賴。詳情還是請(qǐng)看阮神博客。還有官網(wǎng)。
本次demo 只是介紹了局部作用于與全局作用域。
-
- 更改main.jsx文件。同樣我們?cè)黾右徊糠执a。
//增加start var div = document.createElement('div'); div.id = 'example'; document.body.appendChild(div); var h1 = document.createElement('h1'); h1.className="h1"; var t1=document.createTextNode("Hello World"); h1.appendChild(t1); document.body.appendChild(h1); var h2 = document.createElement('h2'); h2.className="h2"; var t2=document.createTextNode("Hello Webpack"); h2.appendChild(t2); document.body.appendChild(h2); //end var React = require('react'); var ReactDOM = require('react-dom'); var style = require('./app.css'); ReactDOM.render( <div> <h1 className={style.h1}>Hello World</h1> <h2 className="h2">Hello Webpack</h2> </div>, document.getElementById('example') );- 更改webpack.config.js
var HtmlwebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './main.jsx',//每次看好打包的入口文件呦 output: { filename: 'bundle.js' }, //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), ], module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ { loader: 'style-loader' }, {//使用module loader: 'css-loader', options: { modules: true } } ] } ] } };- 更改app.css
/* local scope */ .h1 { color:red; } /* global scope */ :global(.h2) { color: blue; }- CMD 鍵入 webpack 打包 ,鍵入 webpack-dev-server --open 開啟server
Asset Size Chunks Chunk Names bundle.js 6.89 KiB 0 [emitted] main index.html 187 bytes [emitted]- 結(jié)果是 有一個(gè)紅色字體的h1 一個(gè)黑色字體的h1 兩個(gè)藍(lán)色字體的h2, 因?yàn)閔2 的class是global的 h1的local的
demo7:使用 uglifyjs 插件
什么事uglifyjs 插件:將輸出的文件bundle.js變到最小。丑化js代碼。
這里需要注意webpack 兩種模式的 產(chǎn)品模式下 uglifyjs插件是默認(rèn)開啟的我們需要在development模式下搞
-
- 更改main.js使用阮神demo中的代碼:
var longVariableName = 'Hello'; longVariableName += ' World'; document.write('<h1>' + longVariableName + '</h1>'); -
- 在webpack.config.js文件中加入如下配置:
mode: 'development',//開發(fā)者模式- 我們先打包一次main.js打包成的bundle.js的大小為3.89kb,然后使用插件。這個(gè)時(shí)候bundle.js可讀
- npm install uglifyjs-webpack-plugin,更改webpack.config.js,加一個(gè)插件其他不更改
var HtmlwebpackPlugin = require('html-webpack-plugin'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin'); module.exports = { entry: './main.js',//每次看好打包的入口文件呦 output: { filename: 'bundle.js' }, //加入html自動(dòng)生成 mode: 'development',//開發(fā)者模式 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), new UglifyJsPlugin(),//開發(fā)者模式下使用插件 ], module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] } };- CMD 鍵入 webpack 打包 ,查看bundle.js大小1.23KB
demo8 :html-webpack-plugin與open-browser-webpack-plugin兩個(gè)插件。
html-webpack-plugin:自動(dòng)生成html插件。這個(gè)插件我們已經(jīng)使用啦,不介紹了。
open-browser-webpack-plugin:自動(dòng)打開瀏覽器插件。
-
- npm install open-browser-webpack-plugin,更改webpack.config.js如下
var HtmlwebpackPlugin = require('html-webpack-plugin'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin'); var OpenBrowserPlugin = require('open-browser-webpack-plugin'); module.exports = { entry: './main.js',//每次看好打包的入口文件呦 output: { filename: 'bundle.js' }, mode: 'development', //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), new UglifyJsPlugin(), new OpenBrowserPlugin({ url: 'http://localhost:8080'//開啟服務(wù)后自動(dòng)打開這個(gè)網(wǎng)址 }) ], module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] } };- CMD 鍵入 webpack 打包 ,鍵入 webpack-dev-server 開啟server,不需要--open了 否則會(huì)打開兩個(gè)頁面
demo9 :Environment flags
在開發(fā)時(shí),有些東西要放出來,產(chǎn)品環(huán)境時(shí)需要屏蔽掉。我們可以定一個(gè)變量去看當(dāng)前的模式。
-
- 更改main.js
document.write('<h1>Hello World</h1>'); if (__DEV__) {//__DEV__ 在webpack.config.js中定義 document.write(new Date()); }- webpack.config.js
var HtmlwebpackPlugin = require('html-webpack-plugin'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin'); var OpenBrowserPlugin = require('open-browser-webpack-plugin'); var devFlagPlugin = new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false')) }); module.exports = { entry: './main.js',//每次看好打包的入口文件呦 output: { filename: 'bundle.js' }, mode: 'development', //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), new UglifyJsPlugin(), new OpenBrowserPlugin({ url: 'http://localhost:8080' }), devFlagPlugin, ], module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] } };- webpack 打包,并輸入cross-env DEBUG=true webpack-dev-server,來控制debug
阮神是想通過命令將當(dāng)前是否是debug傳入到程序中,我們更改一下代碼。官網(wǎng)上介紹可以使用process.env.NODE_ENV來訪問當(dāng)前的mode。
- main.js
document.write('<h1>Hello World</h1>'); if (process.env.NODE_ENV=="development") { document.write(new Date()); }- 直接看頁面。注:更改了config文件需要重新打包其他的不需要。
demo10 :code splitting
code splitting:打包時(shí),分文件打包
-
- main.js
// main.js require.ensure(['./a'], function (require) { var content = require('./a'); document.open(); document.write('<h1>' + content + '</h1>'); document.close(); });- 創(chuàng)建a.js
// a.js module.exports = 'Hello World'; -
- 其他不變,直接webpack打包,多生成了0.bundle.js文件
//wepack 輸出 Asset Size Chunks Chunk Names 0.bundle.js 307 bytes 0 [emitted] bundle.js 2.45 KiB main [emitted] main index.html 187 bytes [emitted] demo 11:Code splitting with bundle-loader
-
- 這個(gè)與demo10 一樣,npm install bundle-loader后直接更改 main.js
// main.js // Now a.js is requested, it will be bundled into another file var load = require('bundle-loader!./a.js'); // To wait until a.js is available (and get the exports) // you need to async wait for it. load(function(file) { document.open(); document.write('<h1>' + file + '</h1>'); document.close(); });- 直接webpack打包:效果是相同的
Asset Size Chunks Chunk Names 0.bundle.js 307 bytes 0 [emitted] bundle.js 2.45 KiB main [emitted] main index.html 187 bytes [emitted] demo12:Common chunk
是自動(dòng)將相同代碼打包成一個(gè)common.js
-
- 這里需要說明,阮神的做法在webpack4中已經(jīng)廢棄了,現(xiàn)在可以直接使用,更改webpack.config.js
var HtmlwebpackPlugin = require('html-webpack-plugin'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin'); var OpenBrowserPlugin = require('open-browser-webpack-plugin'); var webpack = require('webpack'); var devFlagPlugin = new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse(process.env.NODE_ENV || 'false')) }); module.exports = { entry: { bundle1: './main1.jsx', bundle2: './main2.jsx' }, output: { filename: '[name].js' }, mode: 'development', //增加了這個(gè)配置即可 optimization: { splitChunks: { // old CommonsChunkPlugin chunks: "all" }, }, //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), //new UglifyJsPlugin(),//我們想看打包后的文件,注釋掉這個(gè) new OpenBrowserPlugin({ url: 'http://localhost:8080' }), devFlagPlugin, ], module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] } };- 創(chuàng)建main1.jsx main2.jsx
// main1.jsx var React = require('react'); var ReactDOM = require('react-dom'); ReactDOM.render( <h1>Hello World</h1>, document.getElementById('a') ); // main2.jsx var React = require('react'); var ReactDOM = require('react-dom'); ReactDOM.render( <h2>Hello Webpack</h2>, document.getElementById('b') );- 直接webpack打包,會(huì)多一個(gè)vendorsbundle1bundle2.js文件,
Asset Size Chunks Chunk Names bundle1.js 6.72 KiB bundle1 [emitted] bundle1 bundle2.js 6.72 KiB bundle2 [emitted] bundle2 index.html 318 bytes [emitted] vendors~bundle1~bundle2.js 832 KiB vendors~bundle1~bundle2 [emitted] vendors~bundle1~bundle2 demo13 :vendor chunk
作用:將某一部分類庫,打包到vendor js中。需要先 npm install jquery
-
- main.js
var $ = require('jquery'); $('h1').text('Hello World');- webpack .config.js
var HtmlwebpackPlugin = require('html-webpack-plugin'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin'); var OpenBrowserPlugin = require('open-browser-webpack-plugin'); var webpack = require('webpack'); var devFlagPlugin = new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse(process.env.NODE_ENV || 'false')) }); module.exports = { entry: { app: './main.js', vendor: ['jquery'], },//每次看好打包的入口文件呦 output: { filename: '[name].js' }, mode: 'development', optimization: { splitChunks: { // old CommonsChunkPlugin chunks: "all" }, }, //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), //new UglifyJsPlugin(), new OpenBrowserPlugin({ url: 'http://localhost:8080' }), devFlagPlugin, ], module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] } };- webpack 打包
# webpack 輸出 Asset Size Chunks Chunk Names 0.js 552 bytes 0 [emitted] app.js 9.39 KiB app [emitted] app index.html 240 bytes [emitted] vendor.js 305 KiB vendor [emitted] vendor- 說明下,阮神還是用的CommonsChunkPlugin,但是webpack4已經(jīng)廢棄了,其實(shí)本例的最后完成方法就類似于兩個(gè)入口文件了,只不過其中一個(gè)的意思是所有的jquery包,打包到vendor.js中
- 這個(gè)例子最后阮神還介紹了一種不需要一直require包的方法
- webpack.config.js
var HtmlwebpackPlugin = require('html-webpack-plugin'); var UglifyJsPlugin = require('uglifyjs-webpack-plugin'); var OpenBrowserPlugin = require('open-browser-webpack-plugin'); var webpack = require('webpack'); var devFlagPlugin = new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse(process.env.NODE_ENV || 'false')) }); module.exports = { entry: { app: './main.js', vendor: ['jquery'], },//每次看好打包的入口文件呦 output: { filename: '[name].js' }, mode: 'development', optimization: { splitChunks: { name (module) { // generate a chunk name... return; //... } }, }, //加入html自動(dòng)生成 plugins:[ new HtmlwebpackPlugin({ title: 'Webpack-tutorial', filename: 'index.html' }), //new UglifyJsPlugin(), new OpenBrowserPlugin({ url: 'http://localhost:8080' }), devFlagPlugin, //增加定義$ jquery 隨時(shí)可以使用 new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }) ], module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] } };- 刪除掉main.js中的 ,會(huì)發(fā)現(xiàn) var $ = require('jquery');正常使用
demo14:Exposing global variables
作用:定義一些全局變量,并在代碼中使用它。
-
- 創(chuàng)建文件 data.js
var data = 'Hello World';//定義全局變量- 更改 main.jsx 文件
// main.jsx var data = require('data'); var React = require('react'); var ReactDOM = require('react-dom'); ReactDOM.render( <h1>{data}</h1>, document.body );- webpack.config.js 文件
//增加如下配置 externals: { // require('data') is external and available // on the global var data 'data': 'data' }- webpack打包
# webpack 輸出 Asset Size Chunks Chunk Names app.js 837 KiB app [emitted] app Entrypoint app = app.js [./main.js] 189 bytes {app} [built] [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {app} [built] [data] external "data" 42 bytes {app} [built] # 可以看到external data 這個(gè)變量可以require后使用了- 不知到為什么,我使用html-webpack-plugin創(chuàng)建index.html后 不好使,而我在dist同級(jí)目錄下創(chuàng)建一個(gè)index.html放入如下代碼:打包開啟server后,就能夠正常顯示data的數(shù)據(jù)了,最后也沒弄清楚。
<html> <body> <script src="data.js"></script> <script src="app.js"></script> </body> </html> demo 15:React router
關(guān)于這段react 留著以后再研究。
總結(jié)
至此阮神的15DEMO演示完畢,本人也是先從官網(wǎng)看的文檔,看的很迷糊,一些概念性的東西,完全沒頭沒腦的看,通過一些簡(jiǎn)單的配置,可以對(duì)webpack有一個(gè)更好地理解。