翻译它主要是用于学习Webpack,原地址为
安装使用指南
首先,全局安装Webpack和webpack-dev-server
$ npm i -g webpack webpack-dev-server复制代码
然后克隆clone阮一峰的仓库
$ git clone https://github.com/ruanyf/webpack-demos.git复制代码
安装依赖
$ cd webpack-demos$ npm install复制代码
现在开始进入demo*目录并且运行它们
$ cd demo01$ npm run dev复制代码
上面的代码不会自动的打开你的浏览器,需要手动访问
前言:Webpack是什么
Webpack用于构建Javascript模块脚本来给浏览器使用的前端工具。
它和Browserify很像,但是能做更多的事~$ browserify main.js > bundle.js# 上下代码作用相同$ webpack main.js bundle.js复制代码
Webpack需要一个名为webpack.config.js
的配置文件,这个文件就是一个CommonJS的模块(module)
// webpack.config.js的内容module.exports = { entry: './main.js', output: { filename: 'bundle.js' }};复制代码
当建好webpack.config.js
后就能直接运行Webpack,而不加参数
$ webpack复制代码
有一些必须知道的参数选项如下
webpack
——开发时的构建命令webpack -p
——发布产品时的构建命令webpack --watch
——用于增量开发的构建webpack -d
——包括source mapswebpack --colors
——让构建输出更好看
可以在定制webpack.config.js
中的scripts
选项,如下所示
// package.json{ // ... "scripts": { "dev": "webpack-dev-server --devtool eval --progress --colors", "deploy": "NODE_ENV=production webpack -p" }, // ...}复制代码
Demo01:入口文件
入口文件用来Webpack读取它然后构建bundle.js
main.js
就是一个入口文件 // main.jsdocument.write('Hello World
');复制代码
index.html
复制代码
Webpack依据webpack.config.js
来构建bundle.js
// webpack.config.jsmodule.exports = { entry: './main.js', output: { filename: 'bundle.js' }};复制代码
运行下面的命令然后访问
$ cd demo01$ npm run dev复制代码
Demo02:多个入口文件
Webpack
允许多个入口文件存在,在多页面的app中很有用,每个页面有不同的入口文件。
// main1.jsdocument.write('Hello World
');// main2.jsdocument.write('Hello Webpack
');复制代码
index.html
复制代码
webpack.config.js
module.exports = { entry: { bundle1: './main1.js', bundle2: './main2.js' }, output: { filename: '[name].js' }};复制代码
Demo03:Babel-loader
加载器(Loaders)是一些预处理器,用于在Webpack的构建过程前,将你app里的一些资源文件进行转换。
例如,Babel-loader能够将JSX/ES6文件转为普通的JS文件,之后Webpack能够开始构建它们。Webpack官方文档有一个加载器的列表main.jsx
是一个JSX文件 // main.jsxconst React = require('react');const ReactDOM = require('react-dom');ReactDOM.render(Hello, world!
, document.querySelector('#wrapper'));复制代码
index.html
复制代码
webpack.config.js
module.exports = { entry: './main.jsx', output: { filename: 'bundle.js' }, module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } } ] }};复制代码
在上面的代码里需要babel-loader的两个插件babel-preset-es2015和babel-preset-react来转换ES6和React(翻译:现在为废弃了,)
Demo04:CSS-loader
Webpack允许在JS文件中包含CSS,需要CSS-loader对这些CSS进行处理
main.jsrequire('./app.css');复制代码
app.css
body { background-color: blue;}复制代码
index.html
Hello World
复制代码
webpack.config.js
module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, module: { rules:[ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, ] }};复制代码
注意!必须使用两个加载器来转换CSS文件。CSS-loader用来读取CSS文件来转换,另一个Style-loader用来往HTML中插入<style>
标签。
$ cd demo04$ npm run dev复制代码
事实上,Webpack将CSS文件的内容直接插入到index.html
复制代码
Demo5: Image loader
Webpack能够将图片包含进JS文件中
main.jsvar 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);复制代码
index.html
复制代码
webpack.config.js
module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, module: { rules:[ { test: /\.(png|jpg)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] } ] }};复制代码
url-loader
将image文件转为<img>
标签,如果图片大小小鱼8192字节,它将转换为Data url(翻译:图片变为Base64编码,减少请求次数),否则,他将转为普通文件URL。
复制代码
Demo06:CSS Module
css-loader?modules
(请求参数为modules)能够使用CSS Module,CSS Module带给你的JS文件模块中的CSS一个局部作用域,也可以使用:global(selector)
让CSS变为全局作用。
Hello World
Hello Webpack
复制代码
app.css
/* local scope */.h1 { color:red;}/* global scope */:global(.h2) { color: blue;}复制代码
main.jsx
var React = require('react');var ReactDOM = require('react-dom');var style = require('./app.css');ReactDOM.render(, document.getElementById('example'));复制代码Hello World
Hello Webpack
webpack.config.js
module.exports = { entry: './main.jsx', output: { filename: 'bundle.js' }, module: { rules:[ { test: /\.js[x]?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] }};复制代码
访问会看到只有h1
是红色的,因为他的CSS是局部作用域,然后所以h2
都是蓝色的,因为它是全局作用域。
Demo07:UglifyJs Plugin
Webpack用插件系统来扩展他的功能。例如,,它用来压缩JS代码,使得JS文件体积变小。
main.jsvar longVariableName = 'Hello';longVariableName += ' World';document.write('' + longVariableName + '
');复制代码
index.html
复制代码
webpack.config.js
var webpack = require('webpack');var UglifyJsPlugin = require('uglifyjs-webpack-plugin');module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, plugins: [ new UglifyJsPlugin() ]};复制代码
在访问服务器后,可以看到main.js
最小化为如下代码:
var o="Hello";o+=" World",document.write(""+o+"
")复制代码
(翻译:是在bundle.js
的最后几个代码那,是这些代码)
Demo08:HTML Webpack Plugin和Open Browser Webpack Plugin
这个demo用来展示如何加载第三方插件
html-webpack-plugin
能为你创建index.html
,open-browser-webpack-plugin
能够在Webpack加载时打开一个新的浏览器标签(tab) main.js document.write('Hello World
');复制代码
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' }) ]};复制代码
现在你不用手动创建index.html
也不用手动打开浏览器了。
Demo09:环境变量(Environment flags)
使用环境变量让一些代码只能在开发环境时使用。
main.jsdocument.write('Hello World
');if (__DEV__) { document.write(new Date());}复制代码
index.html
复制代码
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]};复制代码
现在传递环境变量给Webpack。打开demo09/package.json
,找到如下scripts
选项
// package.json{ // ... "scripts": { "dev": "cross-env DEBUG=true webpack-dev-server --open", }, // ...}复制代码
Demo10:代码分离
在大型web应用中,将所有代码放入一个文件是十分低效的。Webpack允许你将大型JS文件分成多块。特别的,如果一些代码块只是在某些情况下需要,那么这些代码块会按需加载。
Webpack使用require.ensure
来定义一个分割点 // main.jsrequire.ensure(['./a'], function (require) { var content = require('./a'); document.open(); document.write('' + content + '
'); document.close();});复制代码
require.ensure
告诉Webpack ./a,js
需要从bundle.js
中分离出来作为一个单独的块文件
// a.jsmodule.exports = 'Hello World';复制代码
现在Webpack关心依赖、输出文件、运行时的东西。你不必将多余的东西放到index.html
和webpack.config.js
中
复制代码webpack.config.js
module.exports = { entry: './main.js', output: { filename: 'bundle.js' }};复制代码
访问服务器后,你感觉不到任何不同。实际上,Webpack将构建main.js
和a.js
到不同的块中(bundle.js
和0.bundle.js
),然后从bundle.js
中按需加载0.bundle.js
Demo11:bundle-loader下的代码分离
另一个代码分割的方式是bundle-loader
// main.js// Now a.js is requested, it will be bundled into another filevar 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('' + file + '
'); document.close();});复制代码
require('bundle-loader!./a.js')
告诉Webpack从其他块加载a.js
main.js
构建为bundle.js
,a.js
构建为0.bundle.js
Demo12:通用块
在多个JS脚本中有通用块,通过CommonsChunkPlugin
你能提取不同文件中的通用部分,对于浏览器缓存来节省带宽是非常有用的。
// main1.jsxvar React = require('react');var ReactDOM = require('react-dom');ReactDOM.render(Hello World
, document.getElementById('a'));// main2.jsxvar React = require('react');var ReactDOM = require('react-dom');ReactDOM.render(Hello Webpack
, document.getElementById('b'));复制代码
index.html
复制代码
上面的commons.js
是main1.jsx
和main2.jsx
的通用部分。正如你想的,commons.js
包括react
和react-dom
var webpack = require('webpack');module.exports = { entry: { bundle1: './main1.jsx', bundle2: './main2.jsx' }, output: { filename: '[name].js' }, module: { rules:[ { test: /\.js[x]?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, ] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "commons", // (the commons chunk name) filename: "commons.js", // (the filename of the commons chunk) }) ]}复制代码
Demo13:Vendor chunk
通过CommonsChunkPlugin
,你能从JS脚本提取官方库到单独的文件中
var $ = require('jquery');$('h1').text('Hello World');复制代码
index.html
复制代码
webpack.config.js
var webpack = require('webpack');module.exports = { entry: { app: './main.js', vendor: ['jquery'], }, output: { filename: 'bundle.js' }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.js' }) ]};复制代码
在上面的代码中,entry.vendor:['jquery']
告诉Webpack,jquery
应该被包括到通用块vendor.js
中。
require('jquery')
,而是让$
或者jQuery
作为全局变量,需要使用ProvidePlugin
,它能够自动加载模块而不需要到处import
或者是require
// main.js$('h1').text('Hello World');// webpack.config.jsvar webpack = require('webpack');module.exports = { entry: { app: './main.js' }, output: { filename: 'bundle.js' }, plugins: [ new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }) ]};复制代码
当然,在Demo13中,你需要自己全局加载jquery.js
Demo14:公开全局变量
如果你想用一些全局变量,不需要在Webpack包中包含他们,你可以使用webpack.config.js里的externals
字段
data.js
// data.jsvar data = 'Hello World';复制代码
index.html
复制代码
注意,Webpack只会构建bundle.js
, 而不会构建data.js
data
作为全局变量 // webpack.config.jsmodule.exports = { entry: './main.jsx', output: { filename: 'bundle.js' }, module: { rules:[ { test: /\.js[x]?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, ] }, externals: { // require('data') is external and available // on the global var data 'data': 'data' }};复制代码
此时,你可以require('data')
作为模块变量,实际上它是一个全局变量
// main.jsxvar data = require('data');var React = require('react');var ReactDOM = require('react-dom');ReactDOM.render({data}
, document.body);复制代码
同样可以将react
和react-dom
放入externals
,这样显著的降低构建bundle.js
的时间和文件大小
Demo15:React router
这个Demo使用Webpack来构建React router的官方样例
先想象一个有控制板、收件箱、日历的小应用+---------------------------------------------------------+| +---------+ +-------+ +--------+ || |Dashboard| | Inbox | |Calendar| Logged in as Jane || +---------+ +-------+ +--------+ |+---------------------------------------------------------+| || Dashboard || || || +---------------------+ +----------------------+ || | | | | || | + + | +---------> | || | | | | | | || | | + | | +-------------> | || | | | + | | | | || | | | | | | | | || +-+---+----+-----+----+ +----------------------+ || |+---------------------------------------------------------+复制代码
webpack.config.js
module.exports = { entry: './index.js', output: { filename: 'bundle.js' }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.jsx?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['es2015', 'react'] } } }, ] }};复制代码
index.js
import React from 'react';import { render } from 'react-dom';import { BrowserRouter, Switch, Route, Link } from 'react-router-dom';import './app.css';class App extends React.Component { render() { return (); }};class Dashboard extends React.Component { render() { return (Logged in as Jane
- Dashboard
- Inbox
- Calendar
); }};class Inbox extends React.Component { render() { return (Dashboard
); }};class Calendar extends React.Component { render() { return (Inbox
); }};render((Calendar
), document.querySelector('#app'));复制代码
index.html
复制代码
然后访问