webpack
什么是webpack?
webpack是模块打包机:分析你的项目结构,找到javascript模块以及一些其他 浏览器不能直接运行的拓展语言(scss、typescript)并将它们转换和打包成合适的格式供浏览器使用。
为什么用webpack?
工程化实践
命令行运行
webpack {entry file} {destination for bundled file}
配置webpack.config.js 1.package.json中的script会按照一定顺序查找命令行对应的位置,本地的node_modules/.bin在查找清单中,无论全局还是局部安装webpack都不需要写前面那指明详细的路径了; 2.npm start 执行对应命令;不是start,npm run {script name} 常见命令行:
$ npm install xxx
## 利用npm安装模块到当前命令行所在目录
$ npm install xxx --save
## "package.json"中的"dependencies"
$ npm install xxx -g
## 利用npm安装全局模块
$ npm uninstall xxx ## 删除模块
$ npm uninstall xxx -g ## 删除全局模块
$ npm uninstall xxx --save-dev ## 删除模块并同步parkage.json文件中的"devdenpendencies"字段
$ npm uninstall xxx --save ## 删除模块并同步parkage.json中的"dependencies"字段
webpack --config webpack.conf.dev.js 指定配置文件启动,默认是webpack.config.js
Q:devDenpendencies 和dependencies的区别?
devDependencie是一个对象,配置模块依赖的模块列表,属于开发环境的依赖,比如测试或者文档框架;
Dependencies配置生产环境的依赖,程序正常运行时需要加载的依赖
常用的loader
loaders配置通常包含这几个方面:
module.exports = {
module:{
rules:[
{
test:RegExp,
loader:[{}],
include //exclude:手动添加必须处理的文件(文件夹)或者屏蔽不需要处理的文件,
query:为loaders提供额外配置,兼容性一般。
}
]
}
}
css-loader
使你能够用类似@import url(…)方法实现require()功能
$ npm install css-loader --save-dev
style-loader
$ npm install style-loader --save-dev
将所有计算后的样式表嵌入webpack打包后的js文件中
style-loader css-loader 加载有先后顺序
webpack可以把以指定入口的一系列相互依赖的模块打包成一个文件,这里的模块指的不只是js,也可以是css。也就是说,当你用CommonJs规范去引用css文件时,webpack会把你引用的css文件也打包到最终的生成文件中里。这样我们如何让样式生效呢?有两种方法:一种是,在引入css时,在最后生成的js文件中进行处理,动态创建style标签,塞到head标签里。另一种就是把css样式提取出来单独打包。
vue-loader
stylus-loader
Stylus - 富有表现力的、动态的、健壮的CSS
安装:
$ npm install stylus stylus-loader --save-dev
配置:
// webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\.styl$/,
use:[
"style-loader",
'css-loader',
'stylus-loader'
]
}
]
}
}
post-loader
autoprefixer
postcss-loader 和 autoprefixe为css代码添加前缀;
$ npm install postcss-loader autoprefixer --save-dev
...
use:[
...
{
loader:"postcss-loader"
}
]
项目目录下配置postcss.config.js
module.exports = {
plugins:[
require('autoprefixer')
]
}
编译es6
babel是一个javascript编译平台,可以实现 1.使用最新的js代码 而不用管新标准是否被当前浏览器完全支持; 2.使用基于js进行拓展的语言 比如jsx ts
项目常用组合:bable-core babel-preset-env babel-runtime babel-plugin-transform-runtime
babel-cli
Babel的CLI是一种在命令行下使用babel编译文件的简单方法
$ npm install --global babel-cli
开始编译文件
$ babel example.js
将编译结果输出到终端
$ babel example.js --out-file complied.js
$ babel example.js -o compiled.js
如果把一个目录整个编译到一个新的目录
$ babel src --out-dir lib
$ babel src -d lib
babel-core
用编程的方式使用babel,babel-core的作用是把js代码分析成ast(abstract syntax tree),方便插件分析语法进行处理。有些新语法在低版本 js 中是不存在的,如箭头函数,rest 参数,函数默认值等,这种语言层面的不兼容只能通过将代码转为 ast,分析其语法后再转为低版本 js。
首先安装 babel-core。.
$ npm install babel-core
通过安装插件(plugins) 和 预设(presets 一组插件)来指示babel应该去做什么事情。
插件只是单一功能,比如:
- es2015-arrow-functions
- es2015-classes
安装箭头函数插件
$ npm install --save-dev babel-plugin-transform-es2015-arrow-functions
一个个安装太麻烦,我们将预设和插件写入配置文件,可以写入package.json 中babel属性 或者
babel-preset-env
可以根据声明的环境编译声明环境缺少的的特性代码
安装:
$ npm install babel-preset-env --save-dev
默认配置相当于 babel-preset-latest
babel-preset-latest 就是把所有es2015, es2016, es2017 全部包含在一起了。
babel-polyfill
污染全局变量,在global对象上挂载新特性对象,模拟es6环境,转码新增API。污染模块使用者的全局变量所以不能用于模块和库。
安装
$ npm install babel-polyfill --save
在文件顶部引用
import "babel-polyfill"
babel-runtime babel-plugin-transform-runtime
局部垫片,不污染全局环境,引入帮助函数
安装:
$ npm install babel-plugin-transform-runtime --save-dev
$ npm install babel-runtime --save
配置.babelrc文件:
{"presets":[["env",{
"targets":{
"browsers":[
"last 2 versions","ie >= 7"
]
}
}]],
"plugins":[
"transform-runtime"
]
}
// 不能出现空格或者单引号,必须完全符合json规范
Q:babel-polyfill babel-runtime区别?
Babel-polypill全局垫片(理解为挂载在global对象上),污染全局变量,为应用准备
代码最前端 import “babel-polyfill” 随意使用;
Babel-runtime 局部垫片 为开发框架准备 相当于require(“babel-runtime/core-js/promise.js”)等帮助函数文件
babel-plugin-transfomr-runtime消除多余代码
编译typescript
js的超集
安装:
$ npm i typescipt ts-loader --save-dev ## 官方
$ npm i typescipt awesome-typescript-loader ## 第三方
配置:
tsconfig.js. webpack.config.js
配置选项:
compilerOptions include exclude
module:{
rules:[
{
test:/\.tsx?$/,
use:{
loader:'ts-loader'
}
}
]
}
声明文件
npm install ## types/lodash --save
npm install
提取公共代码
作用:减少代码冗余 提高用户的加载速度 ,将独立通用模块提取出来。
配置:
// webpack.config.js
var webpack = require('webpack)
...
entry: {
// 定义多个入口文件
'common': ['./src/page/common/index.js'],
'index': ['./src/page/index/index.js'],
'login': ['./src/page/login/index.js']
},
plugins:[
new webpack.CommonsChunkPlugin({
name:'common',
filename:'js/base.js'
})
]
// name可以是已经存在的chunk一般指入口文件对应的name,那么会把公共模块的代码合并到这个chunk上,否则会创建名字为name的common chunk进行合并;
// 给出一个数组,根据数组每一项新建插件实例多次
// filename 指定common chunk的文件名相对于webpackConfig.output.path的路径
// chunks 指定的source chunk 指定从哪些chunk当中寻找公共模块,省略该选项的时候默认就是entry chunks
// minChunks 可以是数字需要提取的公共代码最小次数 也可以是函数自定义提取代码逻辑 也可以是infinity不会打包任何模块
// children async属于异步中的应用
// deepChildren 查找共同依赖
// 将入口文件中的节点的打包后的公共部分分离到js/base.js中去,同时还包含common入口节点的所有内容
场景: 单页应用
单页应用 + 第三方依赖
多页应用 + 第三方依赖 + webpack生成代码
添加文件注释
const webpack = require('webpack')
plugins:[
...
new webpack.BannerPlugin('版权所有,违者必究')
]
提取css文件
作用:将css文件从打包后的js文件提取
安装:
$ npm install extract-text-webpack-plugin --save-dev
配置:
// webpack.config.js
var ExtractTextPlugin = require('extract-text-webpack-plugin')
// 提取css
var extreactCss = new ExtractTextPlugin('css/[name].css')
// 提取 stylus
var extractStyl = new ExtractTextPlugin('styl/[name].css')
...
module:{
rules:[
test: /\.css$/,
// ExtractTextPlugin.extract()生成loader用于提取css文件
use: extractCss.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader'
},
{
loader:'postcss-loader'
}
]
})
},
{
test: /\.styl$/,
use: extractStylus.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader'
},
{
loader:'postcss-loader'
},
{
loader: 'stylus-loader'
}
]
})
},
]
}
...
plugins:[
extractCss,
extractStyl
]
html模板
作用:依据一个简单的index.html文件 生成一个自动引用你打包后文件的新index.html 在每次生成到的js文件名称不同时非常有用(比如添加了hash值);
安装:
npm install --save-dev html-webpack-plugin
生成单个目标文件:
const HtmlWebpackPlugin = require('html-webpack-plugin')
...
plugins:[
...
new HtmlWebpackPlugin({
template:''//模板路径
})
]
生成多个目标文件:
// webapck.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin')
...
var getHtmlConfig = function (name) {
return {
template: './src/view/' + name + '.html',
filename: 'view/' + name + '.html', // webpackConfig.output中的路径
inject: true,
hash: true,
chunks: ['common', name] // 打包的模块 针对多入口文件 导入模块的关键
}
...
plugins:[
new HtmlWebpackPlugin('index'),
new HtmlWebpackPlugin('login')
]
####热替换
作用:热模块替换的好处是只替换更新的部分,而不是页面重载。
使用:
1.webpack配置文件中:
new webpack.HotModuleReplacementPlugin()
2.webpack Dev Server中添加 “hot”参数
var config = {
...
devServer:{
contentBase:'./dist',
inline:true,
historyApiFallback:true,
hot:true
}
}
module.exports = config;
产品阶段的构建
创建一个webpack.production.config.js
修改package.json文件中
...
"scripts":{
"build":"NODE_ENV=production webpack --config ./webpack.production.config.js --progress"
}
优化插件
OccurrenceOrderPlugin为组件分配id,通过这个插件webpack可以分析恶化优先考虑使用最多的模块,并为他们分配最小ID;UglifyJsPlugin压缩js代码ExtractTextPlugin分离css js文件
缓存
缓存无处不在,使用缓存的最好方法是保证你的文件名和文件内容是匹配的(内容改变,名称也改变)
webpack可以把一个哈希值添加到打包的文件中去,添加特殊的字符串混合体[name],[id],[hash]到输出文件前面。
{
...
output:{
path:__dirname+"/build",
fileName:"bundle-[hash].js"
}
plugins:[
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin(),
]
....
}
去除build文件中残余文件
使用hash后,导致文件越来越多,需要清除残余文件
clean-webpack-plugin
$ cnpm install clean-webpack-plugin --save-dev
使用:
const CleanWebpackPlugin = require('clean-webpack-plugin');
...
plugins:[
new CleanWebpackPlugin('build/*.*',{
root:__dirname,
verbose:true,
dry:false
})
]
最佳实践
juqery项目中的实践心得
配置文件中必须有一行:
// 全局的jquery某些插件依赖全局的jquery。
// 加载外部的jquery
externals: {
jquery: 'window.jQuery'
}
Vue项目中的实践心得
React项目中的实战心得