webpack
npm init -y npm install webapck webpack-cli --save-dev touch webpack.config.js
在webpack.config.js
中下面添加内容javascript
const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') } };
entry
:工程资源的入口,能够是单个文件,也能够是多个文件,经过每个资源入口,webpack
会一次去寻找它的依赖进行模块打包。咱们能够把entry
理解为整个依赖树的根,每一个入口都将对应一个最终生成的打包结果。output
:这是一个配置对象,经过它咱们能够对最终打包的产物进行配置,这里配置了两个属性,:css
path
:打包资源放置的路劲,必须为绝对路径。filename
:打包结果的文件名。定义好配置文件后,用npx webpack
或者./node_modules/.bin/webpack
执行html
loader
项目中须要引入一个css
文件,若是直接用webpack
去执行就会报错,须要再webpack
中加入loader
机制java
module.exports = { ... module: { rules: [ { // 用正则去匹配 .css 结尾的文件,而后须要使用 loader 进行转换 test: /\.css$/, use: ['style-loader', 'css-loader'] } ] } }
编译以前还须要安装style-loader
和css-loader
node
npm install --save-dev style-loader css-laoder
注意:webpack
use
属性的值是一个使用loader
名称组成的数组,loader
执行的顺序是从后往前的,因为loader
执行有顺序,故不能写成这样use: ['css-loader', 'style-loader']
loader
均可以经过URL queryString
的方式传入参数,好比'css-loader?url'
style-loader
的原理:是将css
的内容使用javascript
的字符串存储起来,在网页执行javascript
时经过DOM
操做,动态地向HTML head
标签里插入HTML style
标签。loader
的方式也能够用Object
来实现use: ['style-loader', { loader: 'css-loader', options: { url: true } }]
plugin
loader
的做用是被用于转换某些类型的模块,而插件则能够用于执行范围更广的任务,插件的范围包括,从打包优化和压缩,一直到从新定义环节中的变量。git
若是想要使用一个插件,咱们只须要require()
它,而后把它添加到plugins
数组中。咱们能够在一个配置文件中由于不一样的目的屡次使用用一个插件,所以咱们可使用new
操做符来建立它的实列。github
上面使用loader
把css
加载到js
中去,如今使用extract-text-webpack-plugin
插件把bundle.js
文件里的css
提取到单独的文件中web
// 提取 css 的插件 const ExtractTextPlugin = require('extract-text-webpack-plugin') module: { rules: [ { // 用正则去匹配 .css 结尾的文件,而后须要使用 loader 进行转换 test: /\.css$/, loaders: ExtractTextPlugin.extract({ //转换 .css须要使用的 loader use: ['css-loader'] }) } ] }, plugins: [ //从 js 文件中提取出来的 .css 文件名称 new ExtractTextPlugin({ filename: 'main.css' }) ]
编译以前须要安装extract-text-webpack-plugin
chrome
npm install --save-dev extract-text-webpack-plugin
执行webpack
时报错须要这样安装
npm install extract-text-webpack-plugin@next
DevServer
安装
npm install webpack-dev-server --save-dev
而后进行简单的配置
devServer:{ port: 3000, publicPath: "/dist" }
而后用./node_modules/.bin/webpack-dev-server
执行
npm i uglifyJSPlugin-webpack-plugin --save-dev
配置文件
const UglifyJSPlugin = require('uglifyjs-webpack-plugin') plugins: [ new UglifyJSPlugin({ //默认是 false 须要手动开启 parallel: true }) ] 或者 optimization: { minimizer: [new UglifyJsPlugin()], },
在代码层面,webpack
支持两种方式进行异步模块加载,一种是CommonJS
形式的require.ensure
,一种是ES6 Module
形式的异步import()
异步加载的脚本不容许使用document.write
,因此将module.js
的代码改为console.log
export const log = function(){ console.log('module.js loaded.') }
编辑app.js
,将module.js
以异步的形式加载进来
import('./module.js').then(module =>{ module.log() }).catch(error => "An error occurred while loading the module") document.write('app.js loaded.')
修改配置
module.exports = { mode: "production", entry: './app.js', output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), publicPath: "./dist" }, }
这里咱们在output
中添加了一个配置项publicPath
,它是webpack
中一个很重要有很容易引发迷惑的配置,当咱们的工程中有按需加载以及图片和文件等外部资源时,就须要它来配置这些资源的路径,不然页面上就会报404
,这里咱们将publicPath
配置为相对于html
的路径,使按需加载的资源生产在dist
目录下,而且能正确地引用到它。
从新打包以后你会发现打包结果中多出一个1.mian.js
,这里面就是未来会被异步加载进来的内容。刷新页面并查看chrome
的network
标签,能够看到页面会请求1.main.js
。它并不来源于index.html
中的引用,而是经过main.js
在页面插入了script
标签来将其引入的。
webpack
的构建特性从2.0.0
版本开始,webpack
开始加入了更多的能够优化构建过程的特性。
tree-shaking
在关于模块的那一篇文章中咱们提到过,ES6 Module
的模块依赖解析是在代码静态分析过程当中进行的。换句话说,它能够在代码的编译过程当中获得依赖树,而非运行时。利用这一点webpack
提供tree-shaking
功能,它能够帮助咱们检测工程中哪些模块有从未被引用到的代码,这些代码不可能被执行到,所以也称为“死代码”。经过tree-shaking
,webpack
能够在打包过程当中去掉这些死代码来减少最终的资源体积。
开启tree-shaking
特性很简单,只要保证模块遵循ES6 Module
的形式定义便可,这意味着以前全部咱们的例子其实都是默认已经开启了的。可是要注意若是在配置中使用了babel-preset-es2015
或者babel-preset-env
,则须要将其模块依赖解析的特性关掉,如:
presets: [ [env, {module: false}] ]
这里咱们测试一下tree-shaking
的功能,编辑module.js
:
// module.js export const log = function() { console.log('module.js loaded.'); } export const unusedFunc = function() { console.log('not used'); }
打开页面查看1.main.js
的内容,应该能够发现unusedFunc
的代码是不存在的,由于它没有被别的模块使用,属于死代码,在tree-shaking
的过程当中被优化掉了。
tree-shaking
最终的效果依赖于实际工程的代码自己,在我对于实际工程的测试中,通常能够将最终的体积减少3%~5%
。整体来看,我认为若是要使tree-shaking
发挥真正的效果还要等几年的时间,由于如今大多数的npm
模块仍是在使用CommonJS
,所以享受不了这个特性带来的优点。
scope-hoisting
scope-hoisting
(做用域提高)是由webpack3
提供的特性。在大型的工程中模块引用的层级每每较深,这会产生比较长的引用链。scope-hoisting
能够将这种纵深的引用链拍平,使得模块自己和其引用的其它模块做用域处于同级。这样的话能够去掉一部分 webpack
的附加代码,减少资源体积,同时能够提高代码的执行效率。
目前若是要开启scope-hoisting
,须要引入它的一个内部插件:
module.exports = { plugins: [ new webpack.optimize.ModuleConcatenationPlugin() ] }
scope-hoisting
生效后会在bundle.js
中看到相似下面的内容,你会发现log
的定义和调用是在同一个做用域下了:
// CONCATENATED MODULE: ./module.js const log = function() { console.log('module.js loaded.'); } // CONCATENATED MODULE: ./app.js log();