官网指南地址javascript
webpack
最出色的功能之一就是,除了JavaScript
,还能够经过loader
引入任何其余类型的文件。webpack.config.js
配置以下:css
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
{
test: /\.xml$/,
use: [
'xml-loader'
]
}
]
}
};
复制代码
配置
HtmlWebpackPlugin
插件自动生成index.html
;配置CleanWebpackPlugin
插件自动清理dist
目录;WebpackManifestPlugin
插件能够提取manifest
。webpack.config.js
配置以下:html
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
复制代码
development
)和生产环境(production
)的构建目标差别很大。live reloading
)或热模块替换(hot module replacement
)能力的 source map
和 localhost server
。bundle
,更轻量的 source map
,以及更优化的资源,以改善加载时间。webpack
配置。webpack-merge
的工具合并配置npm install --save-dev webpack-merge
复制代码
UglifyJSPlugin
或其余工具source map
用仍是不用?library
将经过与 process.env.NODE_ENV
环境变量关联,以决定 library
中应该引用哪些内容new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
复制代码
ExtractTextPlugin
:将 CSS
分离成单独的文件CLI
替代选项:原来用的一些插件如今能够替换成一些优化配置项:例如,--optimize-minimize
标记将在后台引用 UglifyJSPlugin
。和以上描述的 DefinePlugin
实例相同,--define process.env.NODE_ENV="'production'"
也会作一样的事情。而且,webpack -p
将自动地调用上述这些标记,从而调用须要引入的插件。webpack/node/npm
loader/plugins
;必要的话也用在尽可能最少数的必要模块中;能够将很是消耗资源的 loaders 转存到 worker pool
中//使用 include 字段仅将 loader 模块应用在实际须要用其转换的位置中:
{
test: /\.js$/,
include: path.resolve(__dirname, "src"),
loader: "babel-loader"
}
复制代码
Dlls
:使用 DllPlugin
将更改不频繁的代码进行单独编译。这将改善引用程序的编译速度,即便它增长了构建过程的复杂性。Smaller = Faster
:减小编译的总体大小,以提升构建性能。尽可能保持 chunks
小巧。cache-loader
启用持久化缓存。使用 package.json
中的 postinstall
清除缓存目录。thread-loader
能够将很是消耗资源的 loaders
转存到 worker pool
中resolve.modules, resolve.extensions, resolve.mainFiles, resolve.descriptionFiles
中类目的数量,由于他们会增长文件系统调用的次数。symlinks
,能够设置 resolve.symlinks: false
。plugins
,而且没有指定 context
信息,能够设置 resolve.cacheWithContext: false
。UglifyJsPlugin、ExtractTextPlugin、[hash]/[chunkhash]、AggressiveSplittingPlugin、AggressiveMergingPlugin、ModuleConcatenationPlugin
devtool
的设置,会致使不一样的性能差别webpack-dev-server
chunk
的体积,以提升性能tree shaking
tree shaking
是一个术语,一般用于描述移除JavaScript
上下文中的未引用代码(dead-code
)。新的webpack 4
正式版本,扩展了这个检测能力,经过package.json
的sideEffects
属性做为标记,向compiler
提供提示,代表项目中的哪些文件是pure
(纯的ES2015
模块)",由此能够安全地删除文件中未使用的部分。vue
sideEffects
:将文件标记为无反作用 如同上面提到的,若是全部代码都不包含反作用,咱们就能够简单地将该属性标记为 false,来告知 webpack,它能够安全地删除未用到的 export 导出。{
"name": "your-project",
"sideEffects": false
}
复制代码
若是你的代码确实有一些反作用,那么能够改成提供一个数组:java
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js"
]
}
复制代码
bundle
中删除它们。为此,咱们将使用 -p(production)
这个 webpack
编译标记,来启用 uglifyjs
压缩插件。
--optimize-minimize
标记也会在 webpack
内部调用 UglifyJsPlugin
。)webpack 4
开始,也能够经过 mode
配置选项轻松切换到压缩输出,只需设置为 production
。
在
vue
单页应用中,当项目不断完善丰富时,即便使用webpack
打包,文件依然是很是大的,影响页面的加载。若是咱们能把不一样路由对应的组件分割成不一样的代码块,当路由被访问时才加载对应的组件(也就是按需加载),这样就更加高效了。——引自vue-router
官方文档node
非动态加载时的打包状况以下图: jquery
hello
组件的加载方式
改成路由懒加载[import()语法],在进行打包
// import Hello from '@/components/Hello'
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
// component: Hello,
component: () => import('@/components/Hello')
}
]
})
复制代码
4个js
文件,仔细的同窗还发现,app.js
文件的大小加上新多出文件的大小,约等于没有分割打包的app
的大小。js
,在页面首次加载的时候不须要加载他,等到请求相应的页面的时候在去服务器请求它,减少了页面首屏加载的时间。webpack.prod.conf.js
中配置 output.chunkFilename
规定了打包异步文件的格式//webpack.prod.conf.js:生产打包js
//utils.assetsPath是utils.js中封装的一个路径相关的方法
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
/** 本人在本身的工程中删除或修改chunkFilename的配置, 最后仍是都按这个规则生产js文件了, Why? */
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
复制代码
lodash.bundle.js
,在技术概念上“懒加载”它。问题是加载这个包并不须要用户的交互 -- 意思是每次加载页面的时候都会请求它。这样作并无对咱们有不少帮助,还会对性能产生负面影响。//src/index.js
- import _ from 'lodash';
-
- function component() {
+ function getComponent() {
- var element = document.createElement('div');
-
- // Lodash, now imported by this script
- element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
+ var element = document.createElement('div');
+
+ element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+
+ return element;
+
+ }).catch(error => 'An error occurred while loading the component');
}
- document.body.appendChild(component());
+ getComponent().then(component => {
+ document.body.appendChild(component);
+ })
复制代码
客户端(一般是浏览器)获取资源是比较耗费时间的。能够经过命中缓存,以下降网络流量,使网站加载速度更快;然而,缓存的存在可能会使你获取新代码时比较棘手(文件名不变的话)。如何经过必要的配置,以确保
webpack
编译生成的文件可以被客户端缓存,而在文件内容变化后,可以请求到新的文件。webpack
output.filename
进行文件名替换
webpack
在入口 chunk
中,包含了某些样板(boilerplate
),特别是 runtime
和 manifest
。(译注:样板(boilerplate
)指 webpack
运行时的引导代码)webpack
生成的 hash
发生改变,manifest
文件也会发生改变。所以,vendor bundle
的内容也会发生改变,而且失效。因此,咱们须要将 manifest
文件提取出来。CommonsChunkPlugin
将manifest
提取出来
webpack
里每一个模块都有一个 module id
,module id
是该模块在模块依赖关系图里按顺序分配的序号,若是这个 module id
发生了变化,那么他的 chunkhash
也会发生变化。module id
总体发生改变,可能会致使全部文件的chunkhash
发生变化,这显然不是咱们想要的HashedModuleIdsPlugin
,根据模块的相对路径生成一个四位数的hash做为模块id,这样就算引入了新的模块,也不会影响 module id
的值,只要模块的路径不改变的话。new webpack.HashedModuleIdsPlugin()
复制代码
library
除了打包应用程序代码,
webpack
还能够用于打包JavaScript library
;即咱们平时npm install
下来的那种依赖包git
个人demo:element-ui表单的二次封装github
最后,
package.json
中配置"main": "dist/ginna-form.js"
;咱们从node_modules
引入时就靠这个属性来找到对应的文件的哦。
shimming
webpack
编译器(compiler
)可以识别遵循ES2015
模块语法、CommonJS
或AMD
规范编写的模块。然而,一些第三方的库(library
)可能会引用一些全局依赖(例如jQuery
中的$
)。这些库也可能建立一些须要被导出的全局变量。 这些“不符合规范的模块”就是shimming
发挥做用的地方
shim
:一种库(library
)的抽象,这种库能将一个新的API
引入到一个旧的环境中,并且仅靠旧的环境中已有的手段实现。polyfill
就是一个用在浏览器API
上的shim
。
jQuery
做为全局变量,能够被别的组件引用this
置为window
当模块运行在 CommonJS
环境下this
会变成一个问题,也就是说此时的 this
指向的是 module.exports
。在这个例子中,你能够经过使用 imports-loader
覆写 this
:
library
),和下面所展现的代码相似。exports-loader
,将一个全局变量做为一个普通的模块来导出。例如,为了将 file
导出为 file
以及将 helpers.parse
导出为 parse
babel-polyfill
按需加载Babel
是一个普遍使用的转码器,能够将ES6
代码转为ES5
代码,从而能够在现有环境执行,因此咱们能够用ES6
编写,而不用考虑环境支持的问题。Babel
默认只转换新的JavaScript
语法(syntax
),如箭头函数等,而不转换新的API
,好比Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise
等全局对象,以及一些定义在全局对象上的方法(好比Object.assign
)都不会转码;所以咱们须要polyfill
;
babel-preset-env
babel-preset-env
是一个新的preset
,能够根据配置的目标运行环境(environment
)自动启用须要的 babel
插件javascript
代码时,须要使用 N
个 preset
,好比:babel-preset-es201五、babel-preset-es2016
。es2015
能够把 ES6
代码编译为 ES5
,es2016
能够把 ES2016
代码编译为 ES6
。babel-preset-latest
能够编译 stage 4
进度的 ECMAScript
代码。preset
,包括没必要要的。babel-preset-env
的工做方式相似 babel-preset-latest
,惟一不一样的就是它会根据配置的 env
只编译那些还不支持的特性。es20xx presets
了。script-loader
会在全局上下文中对代码进行取值,相似于经过一个 script
标签引入脚本。在这种模式下,每个标准的库(library
)都应该能正常运行AMD/CommonJS
规范版本,但你也想将他们加入 dist
文件,你可使用 noParse
来标识出这个模块noParse:这是module中的一个属性,
做用:不去解析属性值表明的库的依赖
举例:
咱们通常引用jquery,能够以下引用:
import jq from 'jquery'
对于上面的解析规则:
当解析jq的时候,会去解析jq这个库是否有依赖其余的包
咱们对相似jq这类依赖库,通常会认为不会引用其余的包(特殊除外,自行判断)。
因此,对于这类不引用其余的包的库,咱们在打包的时候就没有必要去解析,
这样可以增长打包速率。
因此,能够在webpack的配置中增长noParse属性
(如下代码只须要看module的noParse属性)
module.exports = {
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'dist')
},
module:{
noParse:/jquery/,//不去解析jquery中的依赖库
rules:[ ]
}
}
复制代码
PWA
渐进式网络应用程序(
Progressive Web Application - PWA
),是一种能够提供相似于原生应用程序(native app
)体验的网络应用程序(web app
)。PWA
能够用来作不少事。其中最重要的是,在离线(offline
)时应用程序可以继续运行功能。这是经过使用名为Service Workers
的网络技术来实现的。
//print.js
export default function printMe() {
console.log('I get called from print.js!');
}
//index.js
import printMe from './print.js';
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('./service-worker.js').then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}
function component() {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
var btn = document.createElement('button');
btn.innerHTML = 'Click me and check the console!';
btn.onclick = printMe;
element.appendChild(btn);
return element;
}
document.body.appendChild(component());
//webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
//3个插件都须要npm install --save-dev
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
title: 'Progressive Web Application'
}),
//添加 Workbox
new WorkboxPlugin.GenerateSW({
// 这些选项帮助 ServiceWorkers 快速启用
// 不容许遗留任何“旧的” ServiceWorkers
clientsClaim: true,
skipWaiting: true
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
//package.json配置脚本
"scripts": {
"build": "webpack",
//使用一个简易服务器,搭建出咱们所需的离线体验
//npm install http-server --save-dev
"start": "http-server dist"
},
复制代码
Workbox
,咱们再看下执行 npm run build
时会发生什么clean-webpack-plugin: /mnt/c/Source/webpack-follow-along/dist has been removed.
Hash: 6588e31715d9be04be25
Version: webpack 3.10.0
Time: 782ms
Asset Size Chunks Chunk Names
app.bundle.js 545 kB 0, 1 [emitted] [big] app
print.bundle.js 2.74 kB 1 [emitted] print
index.html 254 bytes [emitted]
precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js 268 bytes [emitted]
service-worker.js 1 kB [emitted]
[0] ./src/print.js 87 bytes {0} {1} [built]
[1] ./src/index.js 477 bytes {0} [built]
[3] (webpack)/buildin/global.js 509 bytes {0} [built]
[4] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 1 hidden module
Child html-webpack-plugin for "index.html":
1 asset
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 2 hidden modules
复制代码
service-worker.js
(或sw.js
) 和体积很大的 precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js
。sw.js
是 Service Worker
文件,precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js
是 sw.js
引用的文件,因此它也能够运行npm start
启动服务。访问 http://localhost:8080/index.html
并查看 console
控制台。在那里你应该看到:SW registered
复制代码
Service Worker
,你应该能够看到你的应用程序还在正常运行。然而,服务器已经中止了服务,此刻是 Service Worker
在提供服务。TypeScript
准备工做:
ts-loader
插件、tsconfig.json
配置文件(和package.json
同级)、ts
文件中如何使用第三方库(ts
声明文件*.d.ts
)
webpack.config.js
配置
tsconfig.json
案例:
npm
安装第三方库时,必定要牢记同时安装这个库的类型声明文件。你能够从 TypeSearch
中找到并安装这些第三方库的类型声明文件。举个例子,若是想安装 lodash
这个库的类型声明文件,咱们能够运行下面的命令:npm install --save-dev @types/lodash
TypeScript
学习