webpack 安装及使用详解步骤
1、安装 2、基本使用 3、创建bundle文件 4、使用配置文件
1、webpack-dev-server自动打包编译 2、html-webpack-plugin自动添加js入口文件
1、加载CSS、less、scss 2、加载图片 3、加载字体
1、开发环境 2、完整版 3、运行时 4、vue-router 5、vue-resource 6、vuex
网页中常见的静态资源:JS(.js .jsx .coffee .ts)、CSS(.css .less .sass .scss)、Images(.jpg .png .gif .bmp .svg)、字体文件Fonts(.svg .ttf .eot .woff .woff2)、模板文件(.ejs .jade .vue)。静态资源使网页加载速度慢,因为要发起很多二次请求;静态资源间存在综复杂的依赖关系。解决办法:合并压缩(sprite、图片的Base64编码等)、解决各个包之间复杂的依赖关系。
webpack是基于Node.js开发的前端项目构建工具。本质上,webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler)。当webpack处理应用程序时,会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有模块打包成一个或多个bundle。官网:https://webpack.github.io/ https://www.webpackjs.com/。
Gulp是基于task任务的,webpack是基于整个项目进行构建的。
一、起步
1、安装
确保已安装Node.js最新的长期支持版本(LTS),因为使用旧版本可能遇到各种问题,可能缺少webpack功能以及/或者缺少相关package包。
包安装出错时,可删除node_modules文件夹,运行npm install重新安装所有包。也可以npm uninstall <包名>卸载相应的包。
(1)全局安装
运行npm i webpack -g全局安装。
(2)本地安装
对于大多数项目,建议本地安装(先全局安装,才能使用webpack命令)。使引入破坏式变更(breaking change)的依赖时,更容易分别升级项目。在项目根目录中运行以下命令安装到项目依赖中。
安装到最新版本:npm install --save-dev webpack
安装到特定版本:npm install --save-dev webpack@<version>
使用webpack 4+版本时,还需要安装CLI:npm install --save-dev webpack-cli,提供命令行(如webpack命令)和打包功能。
2、基本使用
webpack-demo // 根目录
|- package.json
|- webpack.config.js // 配置文件
|- /dist // 发布的文件
|- index.html // 首页
|- bundle.js
|- /src // 源代码
|- /css
|- /js
|- /images
|- main.js // js入口文件
|- /node_modules
创建项目基本的目录结构;运行npm init -y在根目录下创建package.json(项目是中文名使用npm init),使用npm管理项目中的依赖包;运行npm install webpack webpack-cli --save-dev本地安装webpack。
使用npm i jquery -S安装jquery类库。import $ from 'jquery'导入jquery类库。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>起步</title>
</head>
<body>
<ul>
<li>这是第1个li</li>
<li>这是第2个li</li>
<li>这是第3个li</li>
<li>这是第4个li</li>
</ul>
<script src="./bundle.js"></script>
</body>
</html>
/* main.js */
import $ from 'jquery' // 相当于node中,const $=require('jquery')
$(function(){
// 设置背景色隔行变色
$('li:odd').css('backgroundColor','pink');
$('li:even').css('backgroundColor','#ddd');
})
import或require导入包的查找规则:项目根目录中node_modules文件夹->根据包名找对应的文件夹->package.json包配置文件->main属性,指定了该包在被加载时的入口文件。
3、创建bundle文件
“源”代码(/src)是用于书写和编辑的代码,“分发”代码(/dist)是构建过程产生的代码最小化和优化后的“输出”目录,最终将在浏览器中加载。
webpack能够很好地支持import和export语句、及多种其它模块语法。webpack会将代码“转译”,以便旧版本浏览器可以执行。
将src/main.js“转译”为dist/bundle.js:webpack .\src\main.js --output .\dist\bundle.js(入口文件路径 输出文件路径);或npx webpack,将脚本作为入口起点,然后输出为main.js。
4、使用配置文件
在webpack 4中,可以无须任何配置使用,然而大多数项目会需要很复杂的设置,webpack仍然要支持配置文件,这比在终端中手动输入大量命令要高效的多,所以让我们创建一个取代以上使用CLI选项方式的配置文件。
使用配置文件创建bundle:webpack或npx webpack --config webpack.config.js。在控制台直接输入webpack命令执行时,去项目根目录查找配置文件,解析得到导出的配置对象,拿到配置对象中指定的入口和出口,进行打包构建。webpack 4有约定,为了尽量减少配置文件的体积,默认约定了打包的入口是./src/index.js和打包的出口是./dist/main.js。
/* webpack.config.js */
const path=require('path')
module.exports={ // node语法
entry:'./src/main.js', // 项目入口文件,默认为'./src/index.js'
output:{
filename:'bundle.js', // 输出的路径
path:path.resolve(__dirname,'dist') // 输出的文件名
}
}
二、开发
1、webpack-dev-server自动打包编译
使用webpack-dev-server工具实现代码自动打包编译,修改和保存任意源文件,web服务器就会自动重新加载编译后的代码。
(1)运行npm install --save-dev webpack-dev-server将该工具安装到项目的本地开发依赖。该工具依赖于webpack,在本地项目中必须安装webpack。
(2)在命令行直接运行webpack-dev-server命令进行打包,报错,因为webpack-dev-server是本地安装的,无法把它当作脚本命令。需要借助于package.json文件中的指令运行webpack-dev-server命令。在scripts节点下新增"dev": "webpack-dev-server"指令,运行npm run dev。或者新增"start": "webpack-dev-server --open --port 3000 --concentBase dist --hot",运行npm start打开服务器。
(3)命令参数
方式一:修改package.json的script节点
--open 自动在浏览器中打开该端口地址,后面可跟浏览器名称,如firefox
--port 修改运行时的端口号
--host 修改运行时的域名,如127.0.0.1
--contentBase 设置托管的根目录,在浏览器中直接打开该路径下的.html文件
--hot 启动浏览器热更新,不会重新生成bundle.js,只会生成一个.js和.json补丁保存局部更新的代码,并实现浏览器的无重载异步刷新(对css等有效果,对js无效果)
方式二:修改webpack.config.js文件,新增devServer节点
/* webpack.config.js */
const path=require('path')
const webpack=require('webpack') // 启用热更新使用
module.exports={
devServer:{
open:true,
port:3000,
contentBase:'./dist',
hot:true
},
plugins:[
new webpack.HotModuleReplacementPlugin() // 放置热更新的模块对象
]
}
(4)webpack-dev-server打包生成的bundle.js文件,在项目根目录<script src="/bundle.js"></script>。并没有存放到实际的物理磁盘上,而是直接托管到电脑的内存中,在根目录找不到。由于需要实时打包编译,放在内存中速度会非常快。
2、html-webpack-plugin自动添加js入口文件
html-webpack-plugin,自动根据指定页面在内存中生成一个新页面之后,所有的打包好的bundle会自动添加到新页面的body底部。不再需要指定启动目录和手动处理bundle.js的引用路径。
npm install --save-dev html-webpack-plugin。
/* webpack.config.js */
const path=require('path')
const htmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
plugins:[ // 配置插件的节点
new htmlWebpackPlugin({
template:path.join(__dirname,'./dist/index.html'), // 指定模板页面
filename:'index.html', // 指定生成页面名称,浏览器默认打开index.html
title:'Output Management'
})
]
}
三、管理资源
webpack默认只能打包处理JS类型的文件,如需引入任何其它类型的文件,需通过loader 。
webpack处理第三方文件类型的过程:发现要处理的文件不是JS文件,去配置文件中查找有没有对应的第三方loader规则;如果有,调用对应的loader处理这种文件类型,从后往前调用;处理完毕,把处理的结果交给webpack进行打包合并,输出到bundle.js。
1、加载CSS、less、scss
为了从JS模块中import一个CSS文件,需要在module配置中安装并添加style-loader和css-loader。
/* main.js */
import './css/index.css'
import './css/index.less'
import './css/index.scss'
npm install --save-dev style-loader css-loader
npm install --save-dev less less-loader less是less-loader内部依赖,不需要显式定义
npm install --save-dev node-sass sass-loader node-sass是sass-loader内部依赖,不需要显式定义
/* main.js */
import './css/index.css'
import './css/index.less'
import './css/index.scss'
2、加载图片
file-loader和url-loader可以接收并加载任何文件。
npm install --save-dev file-loader 使用file-loader,图片不会被编码为base64
npm install --save-dev url-loader file-loader是url-loader内部依赖,不需要显式定义
{test:/\.(png|svg|jpg|gif)$/,use:'file-loader'}, // 处理图片
{test:/\.(jpg|png|gif|bmp|jpeg)$/,use:'url-loader?limit=7631&name=[hash:8]-[name].[ext]'}
limit给定的值是图片的大小(byte),如果图片大于等于给定的limit值,则不会被转为base64格式的字符串。
图片名默认会被修改为哈希值,防止重名冲突。name=[name].[ext]使图片保持原名,在前面加哈希值解决重名冲突。
3、加载字体
npm install --save-dev file-loader url-loader
{test:/\.(ttf|eot|svg|woff|woff2)$/,use:'url-loader'} // 处理字体文件
四、bable处理高级js语法
webpack默认只能处理部分ES6语法,一些更高级的ES6或ES7语法,需要借助第三方的loader处理,转为低级的语法后,把结果交给webpack打包到bundle.js中。
webpack 4.x | babel-loader 8.x | babel 7.x
npm install -D babel-loader @babel/core @babel/preset-env webpack
npm install -D @babel/runtime @babel/plugin-transform-runtime @babel-runtime是依赖
babel-preset-env是较新的ES语法。(使用了static关键字报错,可能是因为这只是提案,目前不支持)
babel对一些公共方法使用了非常小的辅助代码,如_extend。默认情况下会被添加到每一个需要它的文件中,引入babel runtime作为一个独立模块,来避免重复引入。禁用babel自动对每个文件的runtime注入,而是引入babel-plugin-transform-runtime使所有辅助代码从这里引用。
配置babel的loader规则时,必须把node_modules目录排除。否则,babel会把node_modules中所有的第三方JS文件都打包编译,打包速度非常慢且非常消耗CPU,且即使编译完毕项目也无法正常运行。
/* webpack.config.js */
module.exports={
module:{
rules:[
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/} // 配置babel处理ES6等高级语法
]
}
}
在项目的根目录中,新建一个.babelrc的babel配置文件,该文件是JSON格式,不能写注释,字符串必须用双引号。preset预设,可翻译为语法。
{
"presets":["@babel/preset-env"],
"plugins":["@babel/plugin-transform-runtime"]
}
babel默认启用严格模式,如果要移除严格模式,npm install babel-plugin-transform-remove-strict-mode,并修改.babelrc。
{
"plugins":["transform-remove-strict-mode"]
}
五、Vue
1、开发环境
开发环境下,Vue会提供很多警告来对付常见的错误与陷阱。当使用webpack构建工具时,Vue源码会根据process.env.NODE_ENV决定是否启用开发环境模式。
/* webpack.config.js */
// webpack 4+
module.exports={
mode:'development'
}
// webpack 3及其更低版本
var webpack=require('webpack')
module.exports={
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV':JSON.stringify('production')
})
]
}
2、完整版
npm install --save-dev vue
使用import Vue from 'vue'导入Vue构造函数时,"main": "dist/vue.runtime.common.js",只提供了runtime-only的方式。如果需要在客户端编译模板(如传入一个字符串给template选项,或挂载到一个元素上并以其DOM内部的HTML作为模板),就需要加上编译器,即完整版。否则会报错[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
方式1:
/* main.js */
import Vue from '../node_modules/vue/dist/vue.js'
方式2:每次需要重新启动服务器
/* main.js */
import Vue from 'vue'
/* webpack.config.js */
module.exports={
resolve:{
alias:{
"vue$":"vue/dist/vue.esm.js" // 设置Vue被导入包时的路径
}
}
}
3、运行时
运行时版本相比完整版体积要小大约30%,所以应该尽可能使用这个版本。
npm install --save-dev vue
npm install --save-dev vue-loader vue-template-compiler vue-template-compiler是依赖
/* main.js */
import Vue from 'vue'
import login from './login.vue' // 导入login组件
new Vue({
el:'#app',
render:function(createElement){
return createElement(login)
}
// 简写为render:c=>c(login)
})
/* webpack.config.js */
const VueLoaderPlugin=require('vue-loader/lib/plugin')
module.exports={
module:{
rules:[
{test:/\.vue$/,use:'vue-loader'} // 配置.vue文件
]
},
plugins:[
new VueLoaderPlugin()
]
}
4、vue-router
npm install --save-dev vue
npm install --save-dev vue-router
如果在一个模块化工程中使用它,必须通过Vue.use()明确地安装路由功能。
/* main.js */
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import app from './app.vue'
import router from './router.js'
new Vue({
el:'#app',
render:c=>c(app),
router
})
将<router-link>和<router-view>放到render渲染的<template>中。
/* app.vue */
<template>
<div>
<p>render渲染的组件</p>
<router-link to="/foo">To Foo</router-link>
<router-link to="/bar">To Foo</router-link>
<router-view></router-view>
</div>
</template>
将定义、注册路由抽离为router.js
/* router.js */
import VueRouter from 'vue-router'
import foo from './main/Foo.vue'
import bar from './main/Bar.vue'
var router=new VueRouter({
routes:[
{path:'/foo',component:foo},
{path:'/bar',component:bar}
]
})
export default router // 向外暴露router对象
5、vue-resource
npm install --save-dev vue
npm install --save-dev vue-resource
/* main.js */
import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource)
6、vuex
npm install --save-dev vue
npm install vuex --save
npm install es6-promise --save Vuex依赖Promise,如果浏览器并没有实现Promise(如IE)
/* main.js */
import Vue from 'vue'
// import 'es6-promise/auto'
import Vuex from 'vuex'
Vue.use(Vuex)