Webpack作为前端模块打包工具,根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。由于其能够大大提高开发效率,适合大规模的多页面项目构建,很好地落实到业务而深受企业喜爱,成为目前最流行的前端构建工具之一,被称为“模块打包机”。对于webpack的深入理解及机制介绍将在日后撰文发布,本篇主要详细讲解webpack4.x版本安装、编写配置文件、对脚本、样式和文件的处理(安装loader和插件)及常用命令,实现快速上手与简单理解。
在安装之前确保已经下载安装了node.js,并已经进行npm init 初始化生成了package.json,在此基础上开始用npm安装webpack。
1.1 国内淘宝镜像cnpm
npm由于npm服务器在国外,在安装过程中经常出现下载过慢(慢到头掉)或丢失链接的情况,称“npm被墙”,这时我们可以使用国内的淘宝镜像cnpm,输入下面命令安装:
npm install -g cnpm --registry=https://registry.npm.taobao.org
在之后执行npm命令时,直接用cnpm代替npm,或者也可以把配置写死,即将代理网址写入配置文件中:
//通过config命令
npm config set registry https://registry.npm.taobao.org
npm info underscore
//命令行指定
npm --registry https://registry.npm.taobao.org info underscore
//编辑 ~/.npmrc 加入下面内容
registry = https://registry.npm.taobao.org
注:上面命令写法源于网络,本人没有写入配置文件中,在后面的命令行中都将会使用cnpm代替npm。
2.2 安装webpack
全局安装webpack。此时默认安装webpack最新版,如要安装特定版本,在webpack后加@版本号如:[email protected]。
cnpm install webpack -g
为安装模块到项目node_modules目录下,将模块依赖写入package.json中的devDependencies 节点,输入加上--save-dev的如下命令。后面安装中会出现只有--save 没有-dev,意为安装模块到项目node_modules目录下,将模块依赖写入package.json中的dependencies 节点。主要区别为加dev的用于开发过程中,不会打包进业务代码,如测试工具、打包工具,而加--save会打包进业务代码,是项目运行必备的,如引入jquery。详细的区别见原文:https://www.limitcode.com/detail/59a15b1a69e95702e0780249.html
cnpm install [email protected] --save-dev
安装成功后命令行输入webpack -v能够查看到已安装的webpack版本号。
本篇主要基于webpack 4.x 的安装,在webpack 4 当中,命令行工具cli被单独分离到webpack-cli包当中,以前的版本中它们是在同一个包内,现在需要额外安装webpack-cli才能使用命令:
cnpm install webpack-cli -g
注:在后面的安装过程中踩了很多次版本问题的坑,经过好几波版本升降的操作,建议最初安装时就指定版本,尤其是采用低版本的童鞋。这里放上我目前的node.js版本6.15.1、webpack版本:4.27.1 以及文末的package.json 供大家参考。
这个时候尝试打包,直接输入:webpack ,会发现打包时报错“The 'mode' option has not been set, ......"原因是没有指定没有指定mode为 development(开发模式)或者production(生产模式),这时需要在package.json文件中加入:
"scripts": {
"dev": "webpack --mode development", // 开发模式
"build": "webpack --mode production", // 生产模式
},
使用方法为:命令行输入npm run dev (开发模式输出的index.js没有压缩) 或npm run build (生产模式输出的index.js压缩过,内容紧凑) 可在自动生成的dist文件夹中看到。
webpack.config.js是webpack打包的配置文件,我们在控制台输入一个webpack指令,默认在根目录中查找webpack.config.js并并根据该文件加载与执行相应的依赖。
进入根目录,建立webpack.config.js文件,初次编写主要内容是入口文件路径和打包后文件的存放路径:
const path = require('path');
var config = {
//定义js的入口文件(程序最先读取的文件)
entry: {
'index': ['./src/page/index/index.js'],
'login': ['./src/page/login/index.js'],
},
//定义输出的目标文件
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].js'
},
mode: 'development'
};
module.exports = config;
注:在3.0之后版本配置entry和output中的path不再支持相对路径,只能使用node.js中的一个全局变量__dirname拼接成的绝对路径,它指向当前执行脚本所在的目录。本例是多页应用,计划提取公共代码,因而采用了多个文件的入口设置,输出文件名改为[name].js可以生成多个出口文件名,filename中的js/为使输出文件按格式分装文件夹。
注:每更改后需要重新命令行输入webpack 打包一下才能生效。
我的文件目录供参考:
在本章节模块我将按照步骤顺序讲解命令行内的安装与配置文件的编写,读者也可选择直接跳至章节参考我的完整版webpack.config.js。
3.1 模块化引入jquery
我们在使用jquery时,依旧用require的方式来使用,但是却不希望webpack将它又编译进文件中,模块化引入jquery的好处就是jquery不会打包进bundle中。步骤如下:
1. 命令行安装: cnpm install jquery --save
2. html中引入jquery 第三方库cdn:
3. js中引用: var $ = require('jquery'); $('body').html('
I love webpack
');4. webpack.config.js中的config内添加配置:
externals:{
'jquery': 'window.jQuery'
},
5. 最后命令行webpack打包,测试输出。
3.2 提取公共模块
插件CommonsChunkPlugin的作用是提取代码中的公共代码,然后将公共模块打包到一个独立的文件中,在最开始的时候加载一次,便存到缓存中供后续使用。能够带来速度上的提升。但webpack 4用两个新的配置选项 optimization.splitChunks 和 optimization.runtimeChunk 替代了CommonsChunkPlugin。
1. 在page目录下新建文件夹common
2. webpack.config.js中的config内添加配置:
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: "common",
filename: "js/common.js",
chunks: "initial",
minChunks: 2
}
}
}
},
3. webpack.config.js中config内的entry里添加'common': ['./src/page/common/index.js']:
entry: {
'common': ['./src/page/common/index.js'],
'index': ['./src/page/index/index.js'],
'login': ['./src/page/login/index.js'],
},
4. 最后命令行webpack打包,查看dist中的common.js。
3.3 引入css
1. 命令行安装: cnpm install css-loader style-loader --save-dev
2. webpack.config.js中config内添加配置:
module: {
rules: [
{
test:/\.css$/,
use: ['style-loader','css-loader']
}]
},
3.4 css独立打包
用上面的模块化打包方式会将css打包到对应的js里面,这样要等js加载后才会加载样式,影响用户体验为解决此问题通过 extract-text-webpack-plugin 插件采用css独立打包,将css单独提取出来,以link
的方式注入到文件里面。步骤如下:
1. 命令行安装: cnpm install extract-text-webpack-plugin --save-dev
2. webpack.config.js中开头引入var ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin'); //增加此行
var config = {
entry: {
'common': ['./src/page/common/index.js'],
...
3. webpack.config.js中config内添加配置:
plugins: [
//css单独打包到文件
new ExtractTextPlugin('css/[name].css'),
],
4. webpack.config.js中config内修改module中的rules:
module: {
//css独立通用模块
rules: [
{
test:/\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
},
5. 最后命令行webpack打包,查看输出的index.css。
3.5 对html文件的处理
通过html-webpack-plugin插件用webpack自动生成html可以对多个页面共有的部分实现复用、处理资源的动态路径以及自动加载webpack生成的css、less。步骤如下:
1. 命令行安装: cnpm install html-webpack-plugin --save-dev
2. webpack.config.js中开头引入var HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin'); //添加此行
var config = {
entry: {
'common': ['./src/page/common/index.js'],
...
3. webpack.config.js中config内的plugins里添加:
plugins: [
//css单独打包到文件
new ExtractTextPlugin('css/index.css'),
//html模板的处理
new HtmlWebpackPlugin(getHtmlConfig('index')),
new HtmlWebpackPlugin(getHtmlConfig('login')),
],
4. webpack.config.js中开头定义获取html-webpack-plugin参数的方法:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
//获取html-webpack-plugin参数的方法
var getHtmlConfig = function(name){
return {
template: './src/view/'+name+'.html',
filename: 'view/'+name+'.html',
inject: true,
hash: true,
chunks: ['common',name]
}
};
5. 最后命令行webpack打包
通过html-loader建立多个页面复用的公共部分html:
1. 命令行安装: cnpm install html-loader --save-dev
2. view文件目录里新建个layout文件夹,其中存放某一公共部分html片段,如建立html-head.html,其中存放复用的头文件
......3. 使用时在index.html需要引用的地方加入<%= require('html-loader!./layout/html-head.html') %>
4. 命令行webpack打包
3.6 打包图片与字体
1. 命令行安装: cnpm install url-loader file-loader --save-dev
2. webpack.config.js中config内module里的rules添加:
rules: [
{
test:/\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test:/\.(jpg|png|gif|svg)$/,
use:[{
loader:'file-loader',
options:{
name:'[name].[ext]?[hash]',//可以重写css中引入图片部分
publicPath: '../image/',//可以重新生成图片到新的目录
outputPath: 'image/'
}
}]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [{
loader:'file-loader',
options: {
name: '[name].[ext]',//path为相对于context的路径
context:'src',
publicPath: '../fonts/',
outputPath: 'fonts/'
}
}]
}
]
3. 在css中引用图片、字体进行测试:
@font-face{
font-family: 'EngFont';
src: url('../../fonts/CranberryBlues.ttf') format('truetype');
}
.iconfont{
font-family: EngFont;
}
#img{
width: 300px;
height: 300px;
background-image: url('../../image/owl.jpg');
background-size: 100%;
}
4. 命令行webpack打包。
npm init -y //初始化默认的package.json文件
//npm安装指令
npm install 模块 //安装模块到项目目录下
npm install 模块 -g //全局安装模块
npm install 模块 --save //安装模块到项目目录并在package.json中dependencies写入依赖
npm install 模块 --save-dev //安装模块到项目目录并在package.json中devDependencies写入依赖
//npm卸载指令
npm uninstall 模块 //删除模块,但不删除模块留在package.json中的对应信息
npm uninstall 模块 -g //删除全局模块
npm uninstall 模块 --save //删除模块,同时删除package.json中dependencies的对应信息
npm uninstall 模块 --save-dev //删除模块,同时删除package.json中devDependencies的对应信息
//webpack命令
webpack //对项目进行打包
webpack --watch //监听文件改变和自动编译(打包)
webpack -p //压缩混淆脚本,线上打包,压缩最小化
webpack -d //生成map映射文件,方便调试
webpack --display-modules //打包时显示隐藏的模块
webpack --display-chunks //打包时显示chunks
webpack --display-error-details //显示详细错误信息
1. 个人完整webpack.config.js:(本篇未提及的部分涉及到关于webpack-dev-server的相关配置,详见该篇)
const path = require('path');
const webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
//环境变量配置,dev / online
var WEBPACK_ENV = process.env.WEBPACK_ENV || 'dev';
console.log(WEBPACK_ENV);
//获取html-webpack-plugin参数的方法
var getHtmlConfig = function(name){
return {
template: './src/view/'+name+'.html',
filename: 'view/'+name+'.html',
inject: true,
hash: true,
chunks: ['common',name]
}
};
//webpack config
var config = {
entry: {
'common': ['./src/page/common/index.js'],
'index': ['./src/page/index/index.js'],
'login': ['./src/page/login/index.js'],
},
output: {
path: path.resolve(__dirname, 'dist'), //存放文件的路径
publicPath: '/dist/', //访问文件的路径
filename: 'js/[name].js'
},
externals: {
'jquery': 'window.jQuery'
},
resolve:{
alias : {
util : __dirname + '/src/util',
page : __dirname + '/src/page',
service : __dirname + '/src/service',
image : __dirname + '/src/image'
}
},
plugins: [
//css单独打包到文件
new ExtractTextPlugin('css/index.css'),
//html模板的处理
new HtmlWebpackPlugin(getHtmlConfig('index')),
new HtmlWebpackPlugin(getHtmlConfig('login')),
],
module: {
//css独立通用模块
rules: [
{
test:/\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test:/\.(jpg|png|gif|svg)$/,
use:[{
loader:'file-loader',
options:{
name:'[name].[ext]?[hash]', //可以重写css中引入图片部分
publicPath: '../image/', //可以重新生成图片到新的目录
outputPath: 'image/'
}
}]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [{
loader:'file-loader',
options: {
name: '[name].[ext]', //path为相对于context的路径
context:'src',
publicPath: '../fonts/',
outputPath: 'fonts/'
}
}]
}
]
},
mode: 'development',
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: "commonhaha",
chunks: "initial",
minChunks: 2
}
}
}
},
};
if('dev' === WEBPACK_ENV){
config.entry.common.push('webpack-dev-server/client?http://localhost:8082/');
}
module.exports = config;
2. 个人package.json:
{
"name": "incredible_mall",
"version": "1.0.0",
"description": "incredible_mall �front-end code",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode development",
"build": "webpack --mode production",
"dev_env": "WEBPACK_ENV=dev webpack-dev-server --inline --port 8082",
"dev_win": "set WEBPACK_ENV=dev && webpack-dev-server --inline --port 8082",
"dist": "WEBPACK_ENV=online webpack -p",
"dist_win": "set WEBPACK_ENV=online && webpack -p"
},
"repository": {
"type": "git",
"url": "[email protected]:SuperZZQ/incredible_mall.git"
},
"author": "SuperZZQ",
"license": "ISC",
"devDependencies": {
"ajv": "^6.0.0",
"autoprefixer": "^9.3.1",
"css": "^2.2.4",
"css-loader": "^1.0.1",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^2.0.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"json-server": "^0.14.0",
"loader": "^2.1.1",
"style": "0.0.3",
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"webpack": "^4.27.1",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.10"
},
"dependencies": {
"jquery": "^3.3.1",
}
}
webpack4的安装、配置文件、loader加载及常用命令详解到此就完成了,本篇为个人笔记兼教程,转载请注明出处,不足之处欢迎讨论^_^~。