一、安装:在全局环境下安装
$ npm i -g webpack webpack-dev-server
二、运行命令,如果不能自动打开网页,在浏览器的地址栏输入:http://127.0.0.1:8080
npm run dev
webpack是为浏览器构建JavaScript模块脚本的quan前端工具。它可以类似于Browserify一样,但是能做的更多。
$ browserify main.js > bundle.js
# be equivalent to
$ webpack main.js bundle.js
Webpack需要一个配置文件名叫webpack.config.js,是一个commonJS的模块。有了这个文件之后,可以调用webpack,不需要别的参数。一些常用的命令行:
webpack – building for development webpack -p – building for production (minification) webpack --watch – for continuous incremental building webpack -d – including source maps webpack --colors – making building output pretty
可以在package.json文件中对这些命令做个性化处理。
"scripts": { "dev": "webpack-dev-server --open", "build": "webpack -p" },
执行 npm run dev 就是执行 webpack-dev-server --open,npm run build就是执行webpack -p。
三、入口文件:是webpack用来读取以创建bundle.js的文件。Webpack根据webpack.config.js创建bundle.js。webpack.config.js代码如下:
module.exports = { entry: './main.js', // main.js是入口文件 output: { filename: 'bundle.js' } };
四、多个入口文件:webpack.config.js
module.exports = { entry: { bundle1: './main1.js', bundle2: './main2.js' }, output: { filename: '[name].js' /**注意[name]**/ } };
五、babel 加载器
加载器是预处理程序,在webpack构建过程之前转换应用程序的资源文件。例如,Bable-loader可以将JSX/ES6文件转换成正常的JS文件,之后Webpack开始构建这些JS文件。需要在webpack.config.js里配置module。
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-preset-es2015 和 babel-preset-react(安装) } } } ] } };
题外话:提醒一下JSX的格式
// main.jsx const React = require('react'); const ReactDOM = require('react-dom'); ReactDOM.render( <h1>Hello, world!</h1>, document.querySelector('#wrapper') );
六、css加载器 css-loader
webpack可以在JS文件中加载css文件,使用css-loader
webpack.config.js中的配置
module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, module: { rules:[ { test: /.css$/, use: [ 'style-loader', 'css-loader' ] }, ] } };
需要两个加载器:css-loader 和 style-loader(为了向HTML代码中插入<style>标签)
七、Image loader
webpack.config.js代码:
module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, module: { rules:[ { test: /.(png|jpg)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] } ] } };
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);
url-loader会把图片类型的文件转换到img标签中,当图片的大小小于limit的值,会转换到data URL上??????
八、CSS Module
css-loader?modules 查询参数模块使CSS-modules提供了一个本地作用域的css,可以用:global(selector)关闭。
app.css
/* local scope */ .h1 { color:red; } /* global scope */ :global(.h2) { color: blue; }
九、UglifyJS 插件。webpack有自己的插件系统来拓展它的功能,UglifyJS可以压缩输入文件bundle.js的JS代码。
main.js
var longVariableName = 'Hello'; longVariableName += ' World'; document.write('<h1>' + longVariableName + '</h1>');
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("<h1>"+o+"</h1>")
十、HTML Webpack plugin 和 open browser webpack plugin
HTML Webpack plugin 可以创建一个index.html文件,open browser webpack plugin可以在webpack加载时打开一个新的浏览器标签页
十一、environment flag
就好像是设置一个变量,只有设置了这个变量的环境才可以访问某些代码,例如:
document.write('<h1>Hello World</h1>'); if (__DEV__) { document.write(new Date()); }
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] };
发现package.json有这样的变化
{ // ... "scripts": { "dev": "cross-env DEBUG=true webpack-dev-server --open", }, // ... }
十二、code splitting
对于很多大型网站应用来说,把所有的代码放在一个单独的文件里效率很低,webpack允许我们把一个大型的JS文件分割成几个块,如果在某些情况下只需要某些代码块,则可以俺需要加载这些块。webpack使用require.ensure来定义一个分割点。
main.js
require.ensure(['./a'], function (require) { var content = require('./a'); document.open(); document.write('<h1>' + content + '</h1>'); document.close(); });
require.ensure告诉webpack ./a.js从bundle.js 分离了出来,建立了一个单独的块文件。webpack负责这些dependency,输出文件,和运行时间等,不需要在index.html和webpack.config.js添加其他的代码。webpack实际上建立了两个输出文件,bundle.js 和 0.bundle.js。Webpack实际上将main.js 和 a.js构建为不同的块(bundle.js 和 0.bundle.js),并在需要时从bundle.js加载0.bundle.js。
另外一种代码分割的方式 使用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(); });
十三、common chunk
当多个JS文件拥有公共块时,可以使用插件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') );
<html> <body> <div id="a"></div> <div id="b"></div> <script src="commons.js"></script> <script src="bundle1.js"></script> <script src="bundle2.js"></script> </body> </html>
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) }) ] }
十四、Vendor clunk
可以将脚本中的供应商库从CommonsChunkPlugin中提取到单独的文件中。
main.js
var $ = require('jquery'); $('h1').text('Hello World');
index.html
<html> <body> <h1></h1> <script src="vendor.js"></script> <script src="bundle.js"></script> </body> </html>
webpack.config.js
var webpack = require('webpack'); module.exports = { entry: { app: './main.js', vendor: ['jquery'], // jQuery包含在公共块vendor.js }, output: { filename: 'bundle.js' }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.js' }) ] };
ProvidePlugin 插件可以使一个变量在每个模块中像一个全局变量一样使用,不需要重新import或者require。
// 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' }) ] };
十五、exposing global variables 公开全局变量
如果想使用一些全局变量,但是不想使他们包含在Webpack包里,可以在webpack.config.js中启用external字段。
例如,新建一个data.js
// data.js var data = 'Hello World';
index.html
<html> <body> <script src="data.js"></script> <script src="bundle.js"></script> </body> </html>
但是此时,出口文件只有一个bundle.js 而不是data.js。data可以作为一个全局变量。
webpa.config.js
// 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'] } } }, ] }, externals: { // require('data') is external and available // on the global var data 'data': 'data' } };
可以在我们的入口JS文件中使用这个全局变量。
// main.jsx var data = require('data'); var React = require('react'); var ReactDOM = require('react-dom'); ReactDOM.render( <h1>{data}</h1>, document.body );
也可以把react 和 react-dom 放入externals变量里,方便减少bundle.js的创建时间和大小。