wepback风头正火 ,但是公司一直在用gulp,正好赶上年底活动,借此机会第一次尝试了webpack,说实话webpack真的很强大,内容一层一层递进。
这几天跟着官网跑了一遍,然后写了自己的配置文件,因为活动内容不多,很多强大的功能没有用上,但是相信对于入门来说足够了。
下面来总结并附上源码
当 webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
webpack支持的模块语法有哪些?
ES6,CommonJs,Amd
webpack和gulp的区别?
Webpack可以通过众多loader和plugin完成许多gulp上的功能,但Webpack本质在于模块打包,而gulp的本质在于执行任务;使用webpack-stream包可以实现gulp和webpack的搭配使用
核心概念
1.入口:指定使用哪个模块来作为构建内部依赖图的开始,随后打包成bundle
2.输出:定义输出生产的bundle的位置及文件名;
3.loader:让webpack可以处理非js模块;loader 可以将所有类型的文件转换为webpack 能够处理的有效模块。
4. 插件:执行的任务范围包括从打包优化和压缩,一直到重新定义环境中的变量,目的在于完成一些loader无法完成的任务。
常用配置项
1.mode: ‘development’|| ‘production’ || ‘none’
2.entry: array || obj
3.output: {
path: path.resolve(__dirname, "dist"), // 输出文件的目标路径
filename:’bundle.js’,// 打包后的文件名
publicPath: ‘static’// 输出解析文件目录,url相对于html
}
4.module: {
rules: [
{
test: /.js$/, // 指定使用此loader的文件
use: ‘babel-loader’,
options: { },
include: /src/, // 匹配项
exclude: /node_modules/ // 非匹配项
}
]
}
5.plugins: […instance]
6.devServer: {
host: ‘localhost’,
port: ‘8080’,
contentBase: Boolean|| string || array, // 服务器从哪里获取内容
hot:boolean, // 是否开启webpack模块热替换
open: Boolean, // 是否自动打开浏览器
proxy: { path: targetUrl}, // 代理
…others
}
7.resolve: {
alias: {
test: url
},
extensions: [.js, .json]
}
8.devtool: string || false
可选值:
cheap-eval-source-map
eval-source-map
cheap-source-map
source-map
cheap-module-eval-source-map
…others
常用loader及plugin
loader
Css-loader:解析css中资源路径;
Sass-loader:sass转码为css
Postcss-loader:使webpack可以用postcss处理css
Px2rem-loader: px转换为rem
Style-loader:将css以style标签的形式插入到dom中
Babel-loader:转码js以提高兼容性
url-loader:图片转base64
webpack imagemin-webpack-plugin 压缩图片
file-loader:将文件输出到输出目录并返回文件路径
html-loader:处理html中资源路径
eslint-loader:使js支持eslint
plugin
html-webpack-plugin:根据模板导出html文件,并注入bundle
DinePlugin: 创建编译时可以进行配置的全局变量。
HashedModuleIdsPlugin: 根据模块的相对路径生成一个四位数的hash作为模块id
extract-text-webpack-plugin:分离css
mini-css-extract-plugin:分离css
uglifyjs-webpack-plugin:压缩js
optimize-css-assets-webpack-plugin:压缩css
clean-webpack-plugin: 清空某个目录
cli常用命令
--config 使用指定的配置文件
--env.key=value 指定环境变量
--mode=production 指定模式
--progress 打印编译进度的百分比
--display-error-details 展示错误细节
--define 定义环境变量
-w 观察文件变化,变化后重新执行构建流程
--hot 开启模块热替换
--json > stats.json 将编译结果的各种信息输出为json文件
--profile
捕获编译时每个步骤的时间信息
配置文件编写
前端常见需求:
1) Js压缩
2) Css压缩
3) Css提取
4) 小图片转base64
5) Px转rem
6) Css前缀添加
7) Sass转码
8) Babel转码
9) 文件名加hash
10) 文件编码格式转换(常见utf-8与gbk互转)
11) 代码分离
12) Eslint
13) 模块热替换
14) 配置编译过程的全局变量
15) 打包后的代码注入html中
1. 常用模块变量
__dirname:当前文件夹路径
2. 常用占位符
[hash]:模块标识符的hash(后拼接:‘:n’可指定长度)
[chunkhash]: chunk内容的hash(后拼接:‘:n’可指定长度)
[name]:模块名称
[id]: 模块标识符
3. 配置文件使用commonjs编写的,配置类型有下面几种:
1) 导出一个配置对象
2) 导出一个函数
3) 导出一个promise
代码分离
该功能可以把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。
代码分离的方式:
1.手动配置多个入口文件
2.使用webpack自带的splitChunks功能
3.使用import()动态导入
下面附上自己的web.config.js
//生成html文件 npm i -D html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
//每次打包前清理目录文件 npm i -D clean-webpack-plugin
const CleanWebpackPlugin = require('clean-webpack-plugin');
//js压缩 npm i -D uglifyjs-webpack-plugin
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
//单独打包css,webpack3是利用extract-text-webpack-plugin插件提取单独打包css文件
//webpack4得使用mini-css-extract-plugin npm i -D mini-css-extract-plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
//压缩css npm i -D optimize-css-assets-webpack-plugin
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
//用于打包后的文件转码 npm i webpack-encoding-plugin
const EncodingPlugin = require("webpack-encoding-plugin");
//提取公共模块 请参考https://segmentfault.com/a/1190000012828879
//引入glob正则匹配多页面 npm i -D glob
var glob = require('glob');
//安装webpack npm i -D webpack@<version>(版本号)
//webpack4后将webpack-cli分别出来要自己安装 npm in -D webpack-cli
const webpack = require('webpack');
//处理文件路径的工具
const path = require('path');
//设置变量判断是开发环境还是生产环境 npm i -D cross-env
const devMode = process.env.NODE_ENV !== 'production';
//获取所有路口js,生成一个路径对象.
var getEntry = function () {
var entry = {};
//首先我们先读取我们的开发目录
glob.sync('./source/**/*.js').forEach(function (name) {
var n = name.slice(name.lastIndexOf('source/') + 7, name.length - 3);
n = n.slice(0, n.lastIndexOf('/'));
//接着对路径字符串进行了一些裁剪成想要的路径
entry[n] = name;
});
console.log(entry);
/**
* entry = {
* 'crowd/index' : './source/main/index/index.js',
* 'index/index' : './source/content/index/index.js'
* }
*
**/
//最后返回entry 给 webpack的entry
return entry;
};
module.exports = {
entry: getEntry(), //入口文件
output: { //文件输出位置
path: path.resolve(__dirname, 'dist'), //配置输出路径
filename: "js/[name].bundle.js", //文件输出形式
chunkFilename: "js/[name].chunk.js",
publicPath: '/'//虚拟目录,自动指向path编译目录
},
//tips:chunkFilename网上觉得靠谱的解释
//chunkname是未被列在entry中,却又需要被打包出来的文件命名配置。什么场景需要呢?在按需加载(异步)模块的时候,
//这样的文件是没有被列在entry中的,如使用CommonJS的方式异步加载模块:
// require.ensure(["modules/tips.jsx"], function(require) {
// var a = require("modules/tips.jsx");
// // ...
// }, 'tips');
//tips:一般来说,引入第三方库有一下三种情况:
// 通过CDN引入;
// 通过npm 安装并引入;
// 第三方js文件就在本地
resolve: {//一些配置项,如第三方的js文件就在本地,怎么通过webpack引入
alias: {
$: path.resolve(__dirname, './dist/jquery.js'),
jQuery: path.resolve(__dirname, './dist/jquery.js'),
}
},
plugins: [ //插件
require("autoprefixer"),//引入自动补全前缀,直接引入autoprefixer-loader并没有生效,
//安装postcss-loader并引入autoprefixer时生效,并创建postcss.config.js文件
new webpack.HotModuleReplacementPlugin(),//启动模块热替换
new webpack.NamedModulesPlugin(), //用于启动HMR时可以显示模块的相对路径
new UglifyJsPlugin({}),//js压缩
new MiniCssExtractPlugin({//css分离
filename: devMode ? 'css/[name].css' : 'css/[name].[hash:5].css',
chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash:5].css',
}),
new OptimizeCSSAssetsPlugin({}),//css压缩
//多页应用时配置多个html时,那么就需要实例化该插件多次
new HtmlWebpackPlugin({
template: 'src/html/index.html',
excludeChunks: ['list', 'detail']//配置不允许注入的chunk
}),
new HtmlWebpackPlugin({
filename: 'list.html',
template: 'src/html/list.html',
chunks: ['common', 'list']//允许插入到模板中的一些chunk,不配置此项默认会将entry中所有的chunk注入到模板中
}),
new HtmlWebpackPlugin({
filename: 'detail.html',
template: 'src/html/detail.html',
chunks: ['common', 'detail']
}),
//用来项目的转码
new EncodingPlugin({
encoding: 'GB2312'
}),
//清除dist文件夹
new CleanWebpackPlugin(['dist'])
],
//模块
module: {
rules: [
{
test: /.js$/,
use: [
{
loader: 'babel-loader',//cnpm i -D babel-loader @babel/core @babel/preset-env webpack
options: {//npm i -S babel-polyfill 实现浏览器对不支持API的兼容(兼容旧环境、填补)
presets: ['@babel/preset-env']
}
}
],
exclude: /node_modules/
},
{
test: /.(sa|sc|c)ss$/,
use: [//npm i -D style-loader css-loader
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,//因为MiniCssExtractPlugin不支持热替换,所以当是生产环境时不启用这个插件
'css-loader',
'postcss-loader',//npm i -D postcss-loader
// {网上还有这种写法
// loader: 'postcss-loader',
// options: {
// plugins: () => [
// require('autoprefixer')
// ],
// }
// },
'sass-loader',//使用sass-loader要使用node-loader,npm i -D sass-loader node-sass
{
loader: 'px2rem-loader',//配合flexible实现移动端下的适配 npm i px2rem-loader
// options here
options: {
remUni: 75,
remPrecision: 8
}
}
]
},
{
test: /.(jpg|png|gif|jpeg)$/,
use: [ {//npm i -D url-loader
loader: 'url-loader',// 在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL。
options: {
limit: 10000,//设置字节限制
name: 'img/[name]_[hash:5].[ext]'
}
} ]
}
]
},
//配置开发服务功能 npm i -D webpack-dev-server
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
historyApiFallback: true,
hot: true,
port: 9000,
publicPath:'/',
}
};