什么是webpack
webpack是一种javascript应用程序的静态模块打包器(module bundler)。
什么是babel
Babel 是一个 JavaScript 编译器 Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。webpack2后自带babel-loader。
webpack四个核心概念
-
入口(entry)
入口指webpack要打包(构建内部依赖)的起始文件,默认是
'./src'module.exports={ entry:'./src/xxxx.js' } -
输出(output)
output是用来告诉webpack在哪里输出它创建的包(bundles),以及打包后文件的名字。
const path=require('path') module.exports={ entry:'./src/xxxx.js', output:{ path:path.resolve(__dirname,dist), filename:'suibiannong.xxxx.js' } } -
loader
loader,字面意思,加载器,可以把所有非javascript类型的文件在打包成应用程序所依赖的包前按loader要求转译(因为webpack默认只转译javascript),loader有两个重要属性;
test:用于识别需要转译的特定文件或某些文件use:具体使用的loader名
使用某个loader,只需要npm install xxx-loader -D或者yarn add xxx-loader -D
module.exports= {
/*...*/
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' },
{test:/\.css/,use:[{loader:'css-loader'},{loader:'style-loader']}}
]
}
};
-
插件(plugins)
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。
由于插件可传递参数,选项,所以在引入插件后,需要new插件,
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
webpack其他配置和常用操作
- 模式(mode)
webpack4开始,就加入了mode选项,mode告知 webpack 使用相应模式的内置优化(也就是使用不同的内置插件)。
module.exports = {
mode: 'production' //or 'development'
};
在wp4之前,可通过插件配置process.env.NODE_ENV
- devServer
使用webpack开发,一般还会安装webpack-dev-server,它会创建一个简单的web服务器,用于开发模式时,实时重新加载模块。
示例:yarn add webpack-dev-server --save-dev
module.exports={
/*...*/
devServer:{
contentBase:'./dist' //web服务器建立后,设置dist为可访问文件
}
}
- HMR
webpack热模块(Hot Module Replacement),无需刷新,实时更新各个模块。但它只适用于开发坏境,不适用于生产环境。配置也很简单,只需在的devServer基础上进行配置。
const webpack=require('webpack') //引入内置webpack
module.exports={
/*...*/
devServer:{
contentBase:'./dist',
hot:true //开启热模块
},
plugins:[
new webpack.HotModuleReplacementPlugin() //引入内置热模块插件
]
}
- Source Map
devtool是webpack用来设置资源映射的选项,便于debug及维护,在生产环境中,要生成小的bundle,同时速度要快,就可关闭资源映射,或者酌情使用devtool:'source-map',使用了UglifyJSPlugin插件,要设置插件选项{sourceMap:true}
- 懒加载
懒加载或者按需加载,是一种很好的优化网页或应用的方式。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。
/*index.js*/
import('./src/xx.js').then(module=>{
let xx=module.default //xx.js必须使用的是export default导出
xx()
})
在这里import(路径)返回的是一个Promise,可用Promise.then().catch()等链式操作。也可以用async,await调用。
- tree shaking
tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。 在webpack中,删除未导入代码必须:
-
使用 ES2015 模块语法(即 import 和 export)。
按需导入使用到的模块。
-
在项目 package.json 文件中,添加一个 "sideEffects" 入口。
设置有副作用的文件(也就是不要应用tree shaking的模块),避免误删。
-
引入一个能够删除未引用代码(dead code)的压缩工具(minifier)(例如 UglifyJSPlugin)。
配置要使用的压缩代码工具
- shimming
一些第三方的库(library)可能会引用一些全局依赖(例如 lodash 中的 _)。这些库也可能创建一些需要被导出的全局变量。providePlugin的作用就是如果 webpack 知道这个变量在某个模块中被使用了,那么 webpack 将在最终 bundle 中引入我们给定的 package。(简言之,如果模块使用到了这个全局变量,就生成一个单独的bundle文件,供调用)
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
},
plugins: [
new webpack.ProvidePlugin({
_: 'lodash'
})
]
};
这样我就可以在使用到lodash的地方不用import _ from 'lodash',
同时,如果配合tree shaking,我们还可以只导入包的部分值,例如,这个项目只用到了_.join(),那么可以这样配置:
module.exports={
/*...*/
plugins: [
new webpack.providePlugin({
- _: 'lodash'
+ join:['lodash','join'] //意思是用到join()的地方就是lodash.join()
})
]
}
- 代码分离
代码分离其实是一种思想,要不同模块的代码生成不同的文件,或者提取共有代码为共有文件, 在webpack中,如果有两个入口文件,最后生成两个outputFile,那么避免两个文件生成有重复bundle,我们可以引入webpack的CommonsChunkPlugin
const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
plugins: [
new HTMLWebpackPlugin({
title: 'Code Splitting'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common' // 指定公共 bundle 的名称。
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
- 缓存
缓存是浏览器为节约加载时间从对文件进行缓存,如果文件名变了,那么就会重新读取某个文件,例如lodash是一个单独的bundle,那么修改其他文件后的webpack处理是不会对loadsh重新bundle的,也就是不会修改他的chunkhash。
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
main: './src/index.js',
vendor: [
'lodash'
]
},
plugins: [
new webpack.HashedModuleIdsPlugin(), //对没有修改的文件保持chunkhash值不变
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor' //将lodash提取为单独chunk文件
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest' //将manifest提取为单独chunk文件
})
],
output: {
filename: '[name].[chunkhash].js', //生成的chunk都有一串hash随机数
path: path.resolve(__dirname, 'dist')
}
};
如上配置,每次lodash的chunk文件hash值都不会改变,浏览器也就不会重复读取该文件。
- 生产环境构建
如上所述,有的配置适用于开发及环境,有的配置适用于生产环境,那么webpack配置文件就需要设置为webpack.common.js;webpack.prod.js;webpack.dev.js,
webpack.common.js用来设置基础配置;
webpack.prod.js用来配置生产环境属性;
webpack.dev.js用来配置开发环境属性;
使用webpack-merge包进行webpack文件合并,安装yarn add webpack-merge --save-dev
/*webpack.dev.js*/
const common=require('./webpack.common.js');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports=merge(common,{
plugins: [
new UglifyJSPlugin()
]
})
webpack.dev.js同理进行配置合并。
在package.json中添加脚本;
/*package.json*/
{
scripts:{
"start":"webpack-dev-server --open --config webpack.dev.js",
"build":"webpack --config webpack.prod.js"
}
}
总结
以上是webpack的简单实用总结,更多细节需要查询webpack官方文档