6個demo,webpack+react搭配使用
首先教大家2個新技能
步驟
首先,install Webpack 和 webpack-dev-server.
$ npm i -g webpack webpack-dev-server復(fù)制代碼 # Linux & Mac $ git clone git@github.com:holidaying/webpack-demo.git # Windows $ git clone https://github.com/holidaying/webpack-demo.git : $ cd webpack-demo $ npm install復(fù)制代碼
接下來就可以進行demo演示了.
$ cd demo01 $ webpack-dev-server復(fù)制代碼
用瀏覽器訪問 http://127.0.0.1:8080.
什么是webpack?
Webpack 是前端的打包工具類類似于 Grunt and Gulp.但是有區(qū)別,因為它是模塊化構(gòu)建機制,Webpack可以看做是模塊打包機:它做的事情是,分析你的項目結(jié)構(gòu),找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),并將其打包為合適的格式以供瀏覽器使用。
WebPack和Grunt以及Gulp相比有什么特性
其實Webpack和另外兩個并沒有太多的可比性,Gulp/Grunt是一種能夠優(yōu)化前端的開發(fā)流程的工具,而WebPack是一種模塊化的解決方案,不過Webpack的優(yōu)點使得Webpack可以替代Gulp/Grunt類的工具。
Grunt和Gulp的工作方式是:在一個配置文件中,指明對某些文件進行類似編譯,組合,壓縮等任務(wù)的具體步驟,這個工具之后可以自動替你完成這些任務(wù)。
更多信息.
$ webpack main.js bundle.js復(fù)制代碼
它的配置文件是 webpack.config.js.
// webpack.config.js module.exports={ entry: './main.js', output: { filename: 'bundle.js' } };復(fù)制代碼
有了webpack.config.js,你可以不帶參數(shù)使用webpack
$ webpack復(fù)制代碼
一些命令行選項你應(yīng)該知道。
去構(gòu)建你的項目, 你可以把啟動項寫進package.json
// package.json { // ... "scripts": { "dev": "webpack-dev-server --devtool eval --progress --colors", "deploy": "NODE_ENV=production webpack -p" }, // ... }復(fù)制代碼
目錄
Demo01: 單文件入口 (源碼)
Webpack會入口文件進行打包成bundle.js.
例子, main.js 是單文件入口.
// main.js document.write('<h1>Hello World</h1>');復(fù)制代碼
index.html
<html> <body> <script type="text/javascript" src="bundle.js"></script> </body> </html>復(fù)制代碼
Webpack follows webpack.config.js to build bundle.js.
// webpack.config.js module.exports={ entry: './main.js', output: { filename: 'bundle.js' } };復(fù)制代碼
啟動服務(wù), 訪問 http://127.0.0.1:8080 .
$ webpack-dev-server復(fù)制代碼
Demo02: 多文件入口(源碼)
多個入口文件,實用于多個頁面的應(yīng)用
// main1.js document.write('<h1>Hello World</h1>'); // main2.js document.write('<h2>Hello Webpack</h2>');復(fù)制代碼
index.html
<html> <body> <script src="bundle1.js"></script> <script src="bundle2.js"></script> </body> </html>復(fù)制代碼
webpack.config.js
module.exports={ entry: { bundle1: './main1.js', bundle2: './main2.js' }, output: { filename: '[name].js' } };復(fù)制代碼
Demo03: Babel-loader (源碼)
通過使用不同的loader,webpack通過調(diào)用外部的腳本或工具可以對各種各樣的格式的文件進行處理(更多信息). 例如, Babel-loader Babel其實是一個編譯JavaScript的平臺可以將 JSX/ES6 文件轉(zhuǎn)換成瀏覽器可以識別的js文件. 官方文檔loaders.
main.jsx is a JSX 文件.
const React=require('react'); const ReactDOM=require('react-dom'); ReactDOM.render( <h1>Hello, world!</h1>, document.querySelector('#wrapper') );復(fù)制代碼
index.html
<html> <body> <div id="wrapper"></div> <script src="bundle.js"></script> </body> </html>復(fù)制代碼
webpack.config.js
module.exports={ entry: './main.jsx', output: { filename: 'bundle.js' }, module: { loaders:[ { test: /\.js[x]?$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' }, ] } };復(fù)制代碼
在 webpack.config.js, module.loaders 區(qū)域是用來分配loader的. 像上面的代碼片段使用了 babel-loader 需要安裝插件 babel-preset-es2015 和 babel-preset-react to 編譯成 ES6 and React. 可以用query配置參數(shù)
module: { loaders: [ { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel', query: { presets: ['es2015', 'react'] } } ] }復(fù)制代碼
Demo04: CSS-loader (源碼)
Webpack 允許你在js文件中require CSS , 通過 CSS-loader來預(yù)處理css文件.
main.js
require('./app.css');復(fù)制代碼
app.css
body { background-color: blue; }復(fù)制代碼
index.html
<html> <head> <script type="text/javascript" src="bundle.js"></script> </head> <body> <h1>Hello World</h1> </body> </html>復(fù)制代碼
webpack.config.js
module.exports={ entry: './main.js', output: { filename: 'bundle.js' }, module: { loaders:[ { test: /\.css$/, loader: 'style-loader!css-loader' }, ] } };復(fù)制代碼
但是,你需要使用2中l(wèi)oaders來轉(zhuǎn)換CSS 文件. 第一個是 CSS-loader 來讀取CSS文件, 另外一個是Style-loader 是將style樣式插入到html中。 中間用!連接
啟動服務(wù)后, index.html 有內(nèi)部樣式.
<head> <script type="text/javascript" src="bundle.js"></script> <style type="text/css"> body { background-color: blue; } </style> </head>復(fù)制代碼
Demo05: Image loader (源碼)
Webpack 允許你在js文件中require圖片 , 通過 url-loader和file-loader來預(yù)處理圖片文件.
main.js
var img1=document.createElement("img"); img1.src=require("./small.png"); document.body.appendChild(img1); var img2=document.createElement("img"); img2.src=require("./big.png"); document.body.appendChild(img2);復(fù)制代碼
index.html
<html> <body> <script type="text/javascript" src="bundle.js"></script> </body> </html>復(fù)制代碼
webpack.config.js
module.exports={ entry: './main.js', output: { filename: 'bundle.js' }, module: { loaders:[ { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } ] } };復(fù)制代碼
url-loader 轉(zhuǎn)換圖片文件. 如果圖片的大小小于 8192 bytes,它將會轉(zhuǎn)成base64位的地址; 相反, 它就是普通地址.
參數(shù)前是用?連接的
啟動服務(wù)后, small.png and big.png 將會有一下的地址.
<img src="data:image/png;base64,iVBOR...uQmCC"> <img src="4853ca667a2b8b8844eb2693ac1b2578.png">復(fù)制代碼
Demo06: CSS Module (源碼)
css-loader?modules (the query parameter modules) enables the CSS Modules spec.
CSS Module可以開啟全局變量和局部變量,:global(...)表示全局變量,可以在全局中使用樣式(更多信息)
index.html
<html> <body> <h1 class="h1">Hello World</h1> <h2 class="h2">Hello Webpack</h2> <div id="example"></div> <script src="./bundle.js"></script> </body> </html>復(fù)制代碼
app.css
.h1 { color:red; } :global(.h2) { color: blue; }復(fù)制代碼
main.jsx
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') );復(fù)制代碼
webpack.config.js
module.exports={ entry: './main.jsx', output: { filename: 'bundle.js' }, module: { loaders:[ { test: /\.js[x]?$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['es2015', 'react'] } }, { test: /\.css$/, loader: 'style-loader!css-loader?modules' } ] } };復(fù)制代碼
啟動服務(wù).
$ webpack-dev-server復(fù)制代碼
訪問 http://127.0.0.1:8080 , 你將看到只有第二個 h1 是紅的,因為它是局部, 同時 h2 是藍色的, 因為是h2全局的.
Demo07: UglifyJs Plugin (源碼)
Webpack 可以去掉本身附加的東西,優(yōu)化代碼 UglifyJs Plugin will minify output(bundle.js) JS codes.
main.js
var longVariableName='Hello'; longVariableName +=' World'; document.write('<h1>' + longVariableName + '</h1>');復(fù)制代碼
index.html
<html> <body> <script src="bundle.js"></script> </body> </html>復(fù)制代碼
webpack.config.js
var webpack=require('webpack'); var uglifyJsPlugin=webpack.optimize.UglifyJsPlugin; module.exports={ entry: './main.js', output: { filename: 'bundle.js' }, plugins: [ new uglifyJsPlugin({ compress: { warnings: false } }) ] };復(fù)制代碼
啟動服務(wù)后, main.js 將會壓縮如下.
var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")復(fù)制代碼
Demo08: HTML Webpack Plugin and Open Browser Webpack Plugin (源碼)
這個例子需要加載三個插件
html-webpack-plugin 創(chuàng)建 index.html ,open-browser-webpack-plugin 打開瀏覽器
main.js
document.write('<h1>Hello World</h1>');復(fù)制代碼
webpack.config.js
var HtmlwebpackPlugin=require('html-webpack-plugin'); var OpenBrowserPlugin=require('open-browser-webpack-plugin'); module.exports={ entry: './main.js', output: { filename: 'bundle.js' }, plugins: [ new HtmlwebpackPlugin({ title: 'Webpack-demos', filename: 'index.html' }), new OpenBrowserPlugin({ url: 'http://localhost:8080' }) ] };復(fù)制代碼
啟動 webpack-dev-server.啟動這個需要node7版本以上
$ webpack-dev-server復(fù)制代碼
不用手寫index.html 也不用手動打開瀏覽器 Webpack 可以為你做這些事.
Demo09: 設(shè)置環(huán)境變量 (源碼)
你可以利用環(huán)境變量來控制特定代碼的輸出
main.js
document.write('<h1>Hello World</h1>'); if (__DEV__) { document.write(new Date()); }復(fù)制代碼
index.html
<html> <body> <script src="bundle.js"></script> </body> </html>復(fù)制代碼
webpack.config.js
var webpack=require('webpack'); var devFlagPlugin=new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false')) }); module.exports={ entry: './main.js', output: { filename: 'bundle.js' }, plugins: [devFlagPlugin] };復(fù)制代碼 # Linux & Mac $ env DEBUG=true webpack-dev-server # Windows $ set DEBUG=true $ webpack-dev-server復(fù)制代碼
Demo10: Code splitting (源碼)
對于大型項目,把所有代碼編譯到一個文件并不是有效的, Webpack 允許你把代碼分成好多塊. 特別是某種情況下,只需要個別代碼這些塊可以按需加載。
在commonjs中有一個Modules/Async/A規(guī)范,里面定義了require.ensure語法。webpack實現(xiàn)了它,作用是可以在打包的時候進行代碼分片,并異步加載分片后的代碼。用法如下:
require.ensure([], function(require){ var list=require('./list'); list.show(); });復(fù)制代碼
此時list.js會被打包成一個單獨的chunk文件,大概長這樣:
1.fb874860b35831bc96a8.js
可讀性比較差。我在上一篇結(jié)尾也提到了,給它命名的方式,那就是給require.ensure傳遞第三個參數(shù),如:
require.ensure([], function(require){ var list=require('./list'); list.show(); }, 'list');復(fù)制代碼
這樣就能得到你想要的文件名稱:
首先,你需要用 require.ensure to 來定義一個分割的點. (官方文檔)
// main.js require.ensure(['./a'], function(require) { var content=require('./a'); document.open(); document.write('<h1>' + content + '</h1>'); document.close(); });復(fù)制代碼
require.ensure 告訴 Webpack ./a.js 應(yīng)該從 bundle.js 中分離成一個單獨的塊
// a.js module.exports='Hello World';復(fù)制代碼
Now Webpack takes care of the dependencies, output files and runtime stuff. You don't have to put any redundancy into your index.html and webpack.config.js.
<html> <body> <script src="bundle.js"></script> </body> </html>復(fù)制代碼
webpack.config.js
module.exports={ entry: './main.js', output: { filename: 'bundle.js' } };復(fù)制代碼
啟動服務(wù).
$ webpack-dev-server復(fù)制代碼
在界面上, 你感覺不到任何不一樣的地方. 但是, Webpack 已經(jīng)把 main.js 和 a.js 編譯成(bundle.js 和 1.bundle.js)的塊。
Demo11: 通過bundle-loader進行代碼分裂 (源碼)
dem10是一種,另一種是利用bundle-loader.
// 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(); });復(fù)制代碼
require('bundle-loader!./a.js') tells Webpack to load a.js from another chunk.
Now Webpack will build main.js into bundle.js, and a.js into 1.bundle.js.
Demo12: Common chunk (源碼)
利用webpack.optimize.CommonsChunkPlugin,你可以共通的組件,代碼塊分離出來
// 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') );復(fù)制代碼
index.html
<html> <body> <div id="a"></div> <div id="b"></div> <script src="init.js"></script> <script src="bundle1.js"></script> <script src="bundle2.js"></script> </body> </html>復(fù)制代碼
webpack.config.js
var CommonsChunkPlugin=require("webpack/lib/optimize/CommonsChunkPlugin"); module.exports={ entry: { bundle1: './main1.jsx', bundle2: './main2.jsx' }, output: { filename: '[name].js' }, module: { loaders:[ { test: /\.js[x]?$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['es2015', 'react'] } }, ] }, plugins: [ new CommonsChunkPlugin('init.js') ] }復(fù)制代碼
Demo13: Vendor chunk (源碼)
利用webpack.optimize.CommonsChunkPlugin,你可以把第三方庫抽離出來
main.js
var $=require('jquery'); $('h1').text('Hello World');復(fù)制代碼
index.html
<html> <body> <h1></h1> <script src="vendor.js"></script> <script src="bundle.js"></script> </body> </html>復(fù)制代碼
webpack.config.js
var webpack=require('webpack'); module.exports={ entry: { app: './main.js', vendor: ['jquery'], }, output: { filename: 'bundle.js' }, plugins: [ new webpack.optimize.CommonsChunkPlugin(/* chunkName=*/'vendor', /* filename=*/'vendor.js') ] };復(fù)制代碼
If you want a module available as variable in every module, such as making $ and jQuery available in every module without writing require("jquery"). You should use ProvidePlugin (官方文檔).
// main.js $('h1').text('Hello World'); // webpack.config.js var webpack=require('webpack'); module.exports={ entry: { app: './main.js' }, output: { filename: 'bundle.js' }, plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery", "window.jQuery": "jquery" }) ] };復(fù)制代碼
插件會執(zhí)行兩次這個方法,第一次將公共的第三方代碼抽離移到vendor的塊中,這個過程之前也講過會將運行時runtime也轉(zhuǎn)移到vendor塊中,第二次執(zhí)行則是將運行時runtime抽離出來轉(zhuǎn)移到manifest塊中。這步操作解決了緩存問題。
這樣處理,最后會生成3個打包文件chunk,app.js是業(yè)務(wù)代碼,vendor則是公共的第三方代碼,manifest.js則是運行時。
Demo14: Exposing global variables (源碼)
webpack可以不處理應(yīng)用的某些依賴庫,使用externals配置后,依舊可以在代碼中通過CMD、AMD或者window/global全局的方式訪問。如果你想引入一些全局變量, 但是不想被加載處理, 你可以在 webpack.config.js 使用 externals 模塊 (官方文檔).
有時我們希望我們通過script引入的庫,如用CDN的方式引入的jquery,我們在使用時,依舊用require的方式來使用,但是卻不希望webpack將它又編譯進文件中。
例子, data.js.
var data='Hello World';復(fù)制代碼
We can expose data as a global variable.
// webpack.config.js module.exports={ entry: './main.jsx', output: { filename: 'bundle.js' }, module: { loaders:[ { test: /\.js[x]?$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['es2015', 'react'] } }, ] }, externals: { // require('data') is external and available // on the global var data 'data': 'data' } };復(fù)制代碼
現(xiàn)在, 你可以require data 作為模塊化引入進來使用. 但是實際上是一個全局變量
// main.jsx var data=require('data'); var React=require('react'); var ReactDOM=require('react-dom'); ReactDOM.render( <h1>{data}</h1>, document.body );復(fù)制代碼
Demo15: 熱模塊替換/熱更新 (源碼)
Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running without a page reload.
通過webpack-dev-server.你可以使用2中方式 來進行熱模塊替換
(1) Specify --hot and --inline on the command line
$ webpack-dev-server --hot --inline復(fù)制代碼
參數(shù)的意思:
(2) 修改 webpack.config.js.
webpack.config.js 如下所示.
var webpack=require('webpack'); var path=require('path'); module.exports={ entry: [ 'webpack/hot/dev-server', 'webpack-dev-server/client?http://localhost:8080', './index.js' ], output: { filename: 'bundle.js', publicPath: '/static/' }, plugins: [ new webpack.HotModuleReplacementPlugin() ], module: { loaders: [{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['es2015', 'react'] }, include: path.join(__dirname, '.') }] } };復(fù)制代碼
啟動服務(wù)
$ webpack-dev-server復(fù)制代碼
訪問 http://localhost:8080, 你可以在瀏覽器上看到 'Hello World' .
不要關(guān)閉服務(wù).打開終端找到 App.js, 同時修改 'Hello World' 為 'Hello Webpack'. 保存后,你就可以在瀏覽器上看到數(shù)據(jù)更新了
App.js
import React, { Component } from 'react'; export default class App extends Component { render() { return ( <h1>Hello World</h1> ); } }復(fù)制代碼
index.js
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));復(fù)制代碼
index.html
<html> <body> <div id='root'></div> <script src="/static/bundle.js"></script> </body> </html>復(fù)制代碼
Demo16: React router例子 (源碼)
利用webpack做的例子 React-router's 官方例子.
Let's imagine a little app with a dashboard, inbox, and calendar.
者:lzg9527
轉(zhuǎn)發(fā)鏈接:https://segmentfault.com/a/1190000022956602
合Vue.js(前端框架)和Express(后端框架)進行全棧開發(fā)時,你需要關(guān)注幾個關(guān)鍵點以實現(xiàn)前后端的高效協(xié)作和數(shù)據(jù)交互。以下是一些開發(fā)要點:
結(jié)合Vue.js和Express進行全棧開發(fā),關(guān)鍵在于理解前后端職責(zé)的劃分,實現(xiàn)清晰的數(shù)據(jù)交互流程,以及利用各自框架的優(yōu)勢來提升開發(fā)效率和應(yīng)用性能。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。