webpack 的使用
模块化开发
为什么用模块化开发?
原因1:主要是js文件依赖于导入顺序几乎是强制性的,当导入的多个js文件使用相同的变量名时,就会出现下层变量名覆盖上层变量名情况。
解决1:使用闭包函数,形成局部作用域
(function(){
var flag = true
})()
问题2:当使用闭包函数时,文件之间变量就不能被引用
解决2:在闭包函数内定义一个对象,并把它返回
var moduleA = (function () {
var obj = {};
var flag = true;
obj.flag = flag;
return obj
})()
这样,在其它文件下直接通过modelA.flag拿到变量,但是现在模块化已经有成熟的模板。
已存在的模板规范:
CommonJS,AMD,CMD, ES6的Modules,
模板化的核心:导入和导出,如:
CommonJS导入module.exports = { flag: ture, test(a, b) { return a + b }, demo(a, b){ return a * b } }
CommonJS的导入let {test, demo, flag} = require("modelA") // 等同于 let mA = require('moduleA'); let test = mA.test; let demo = mA.demo; let flag = mA.flag;
ES6中的模块化
export和import基本使用
在a.js文件代码
var flag = true;
function sum(a, b) {
return a + b
}
export {
flag, sum
}
在b.js文件下导入,全部导入可以使用*
import {sum} = from "./a.js";
console.log(sum(2, 3));
其他导出方式
导出变量
export let num = 100;
导出函数/类
export function sum(a, b) {
return a + b
}
// 导出类(ES6语法)
export class Person() {
run () {
return "running...."
}
}
export default
某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名
export default function () {
return "export default"
}
// 导入使用
import myFunc from "./info.js"
注意: export default在同一模块中,有且只能存在一个
webpack 使用
介绍
At its core, webpack is a static module bundler for modern JavaScript applications.
从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具
主要功能:把各种模块化开发的代码,打包成大多数浏览器都能识别的代码。比如处理模块之间的关系;压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。

和grunt/gulp相比
-
grunt/gulp的核心时Task- 配置一系列的
task,并且定义task要处理的事务 - 让
grunt/gulp来一次执行这些task,让整个流程自动化 grunt/gulp也被称为前端自动化任务管理工具
- 配置一系列的
-
grunt/gulp的task使用方式,把src下面的所有js文件转换成ES5的语法
const gulp = require("gulp");
const babel = require("gulp-babel");
gulp.task("js", () =>
gulp.src("src/*.js")
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest("dist"))
);
-
什么情况下用
grunt/gulp?- 如果项目内只使用简单模块化,甚至没有用到
- 只是需要进行简单的合并、压缩
-
grunt/gulp和webpack有什么不同grunt/gulp更加强调的时前端流程的自动化webpack更加强调的模块化开发管理
webpack安装
官网:https://webpack.js.org
- 先安装node,最好是10版本以上
window下安装:直接到官网下载https://nodejs.org/zh-cn/
linux下安装指定版本:
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install nodejs
- 安装cnpm,修改镜像源
npm install -g cnpm --registry=https://registry.npm.taobao.org
- 安装webpack(指定为3.6版本,用为vue2依赖该版本)
#全局安装
cnpm install webpack@3.6.0 -g
#局部安装,主要用于package.json中定义了scripts时,包含了webpack命令,那么使用的就是局部webpack'
cnpm install webpack@3.6.0 --save-dev
webpack简单使用
- 创建以下文件夹
- dist文件夹:用于存放之后的打包文件
- src文件夹:用于存放我们写的源文件
- main.js:项目的入口文件
- info.js:可以是各种模块化方式导出
- index.html:首页
// info.js 文件(使用ES6的module)
export const name = 'sun';
export const age = 18;
// math.js(使用CommandJS)
function add(num1, num2) {
return num1 + num2
}
function mul(num1, num2) {
return num1 * num2
}
module.exports = {
add,
mul
}
// main.js
// 使用commandJS
const {add, mul} = require('./mathUtils.js')
console.log(add(20, 30));
// 使用ES6
import {name, age, height} from "./info";
console.log(name);
console.log(age);
当代码编写完之后,将程序打包到dist文件夹内,只需要打包main.js文件,webpack会自动处理依赖关系。
webpack src/main.js dist/bundle.js
之后,直接在index.html文件内引入bundle.js文件就可以使用了
webpack.config.js配置
在项目目录下,创建webpack.config.js文件,
const path = require('path')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'), // path是一个绝对路径
filename: 'bundle.js'
},
}
由于需要使用内置path模块,使用npm init来初始化生成package.json文件
{
"name": "webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
},
"author": "",
"license": "ISC" # 开源标志
把webpack和npm run bulid建立映射
需要在scripts脚本中,加上bulid
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "",
"license": "ISC",
}
这时候执行build时,是使用的局部webpack(终端直接使用webpack,都是全局的), 安装:cnpm install webpack@3.6.0 --save-dev,会在package.json中多了"devDependencies": {"webpack": "^3.6.0"}
webpack使用css文件的配置
主要功能:加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等
中文网站:https://www.webpackjs.com/loaders/
- 安装
cnpm install css-loader --save-dev
- 在
webpack.config.js配置
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}}
- 注意事项
css-loader只负责将css文件经行加载,不负责渲染- 使用
style-loacer负责将样式添加到DOM中 - 使用多个
loader时,加载顺序是从右往左,需要先加载css-loader
webpack 相关文件处理
less、scss、stylus文件处理
定义一个less文件
@fontSize: 50px;
@fontColor: red;
body {
font-size: @fontSize;
color: @fontColor;
}
也是需要加载loader,
$ npm install less-loader less --save-dev
less是转换器,把
webpack下配置
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: [
{
loader: 'style-loader', // creates style nodes from JS strings
},
{
loader: 'css-loader', // translates CSS into CommonJS
},
{
loader: 'less-loader', // compiles Less to CSS
},
],
},
],
},
};
最后在入口文件`main.js 文件下引入:
require("css/test.less")
图片处理
当在css使用图片样式时,
body{
background: url(../imgs/test.jpg)
}
需要使用url-loader,
npm install --save-dev url-loader
修改webpack.config配置文件
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
// options内是参数
options: {
limit: 8192,
},
},
],
},
说明:
- 当图片大小小于limit时,会将图片编译成base64格式
- 当图片大小大于limit时,会使用file-loader模式加载,这时会在dist文件内生成一个相同的图片,如果找不到,则需要在
output下配置publicPath: 'dist/',会自动在url内加上dist/路径 options参数除了limit还有name参数,使用方法:
options: {
limit: 8192,
name: 'img/[name].[hash:8].[ext]'
}
// 说明:
// img/ : 路径,文件要打包到的文件夹
// name : 获取图片原来的名字,放到该位置
// hash:8 : 为了防止图片冲突,使用hash,但只保留8位
// ext : 使用图片原来的扩展名
ES6语法处理
为了一些浏览器支持,把ES6语法转成ES5语法
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js文件
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
]}
使用vue的配置
因为后续项目运行时也会使用Vue,所以不是开发时依赖
npm install Vue --save
版本问题:
runtime-only,代码中,不可以有任何template
runtime-compiler,代码中可以有template,因为compiler可以用于编译模板
使用时:
import Vue from "vue"
new Vue({
el: "#app",
data: {
msg: "Hello"
}
})
当报runtime-only错误时,需要配置webpack.config.js:
moule.exports = {
resolve: {
alias: {
"vue$": "vue/dist/vue.esm.js"
}
}
}
一般书写时,不会修改index.html文件,html代码写到template下:
new Vue({
el: "#app",
template: `
<div>
<h2>{{ msg }}</h2>
</div>
`,
data: {
msg: "Hello"
}
})
最后的结果时,template会自动替换掉index.html内的<div id="app"></div>
最终方案,使用vue文件
main.js文件:
new Vue({
el: '#app',
template: '<App/>',
components: {
App
}
})
app.vue文件:
<template>
<div>
<h2 class="title">{{message}}</h2>
<button @click="btnClick">按钮</button>
<h2>{{name}}</h2>
<Cpn/>
</div>
</template>
<script>
import Cpn from './Cpn'
export default {
name: "App",
components: {
Cpn
},
data() {
return {
message: 'Hello Webpack',
name: 'coderwhy'
}
},
methods: {
btnClick() {
}
}
}
</script>
<style scoped>
.title {
color: green;
}
</style>
需要安装vue-loader和vue-template-compiler组件:
npm install --save-dev vue-loader vue-template-compiler
配置webpack.config.js文件:
{
test: /\.vue/,
use:["vue-loader", ]
}
编译时报错1:
vue-loader was used without the corresponding pllugin....,
原因:vue-loader从14版本往后需要配置插件,
解决办法:使用14以下的版本(直接在package.json 下改版本,然后执行npm install),或安装插件
编译报错2:
not fond: Error: Can't resolve './Cpn',可能是不能省略.vue后缀,需要在webpack.config.js配置:
moule.exports = {
resolve: {
extensions: ['.js', '.css', '.vue'],
}
}
plugin插件使用
- 什么是plugin?
- webpack插件,对webpack现有功能的各种扩展,比如打包优化、文件压缩等
- loader和plugin的区别?
- loader主要用于转换某些类型模块,它是一个转化器
- plugin是插件,它是对webpack本身的扩展,是一个扩展器
- plugin的使用过程:
- 通过npm安装需要使用的plugin
- 在webpack.config.js的plugins中配置插件
添加版权信息的Plugin
BannarPlugin属于webpack自带的插件,使用方式:
const path = require("path");
const webpack = require("webpack")
module exports = {
...
plugins: [
new webpack.BannerPlugin("最终解释权归sun所有")
]
}
打包html的Plugin
HtmlWebpackPlugin插件作用:
- 在dist生成index.html文件
- 将打包的js文件,自动通过script标签插入到body中
安装HtmlWebpackPlugin插件:
npm install html-webpack-plugin --save-dev
使用插件:
const path = require("path");
const webpack = require("webpack");
const htmlWebpackPlugin = require("html-webpack-plugin")
module exports = {
...
plugins: [
new webpack.BannerPlugin("最终解释权归sun所有"),
new htmlWebpackPlugin({
template: "index.html"
})
]
}
js压缩的Plugin
安装:(这里指定版本,为了和CLI2保持一致)
npm install uglifyjs-webpack-plugin@1.1.1 --seve-dev
使用:
const path = require("path");
const webpack = require("webpack");
const htmlWebpackPlugin = require("html-webpack-plugin")
const uglifyjsWebpackPlugin = require("uglifyjs-webpack-plugin")
module exports = {
...
plugins: [
new webpack.BannerPlugin("最终解释权归sun所有"),
new htmlWebpackPlugin({
template: "index.html"
}),
new uglifyjsWebpackPlugin()
]
}
这里会取消所有注释,包括版权的BannerPlugin的内容。
webpack-dev-server
本地服务器,基于node.js搭建,内部使用express框架,会在内存中生成dist文件,可以让浏览器很快的自动刷新修改后的结果。
需要下载webpack-dev-server模块
npm install --save-dev webpack-dev-server@2.9.1
配置webpack.config.js文件:
module.export = {
...
devServer: {
contentBase: "./dist",
inline: true
}
}
包含的参数:
- contentBase: 为哪个文件夹提供服务
- port:端口号
- inline:页面实时刷新
- historyApiFallback:在SPA页面中,依赖HTML5的history模式
还需要在package.json中的script配置
- --open:表示直接打开浏览器
"Scripts": {
...
"dev": "webpack-dev-server --open"
}
webpack配置文件分离
需要安装webpack-merge模块,
npm install webpack-merge --save-dev
建立bulid文件专门放置配置文件
build
|----base.config.js
|----prod.config.js
|----dev.config.js
base.config.js文件内容:
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 13000,
name: 'img/[name].[hash:8].[ext]'
},
}
]
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
},
{
test: /\.vue$/,
use: ['vue-loader']
}
]
},
resolve: {
// alias: 别名
extensions: ['.js', '.css', '.vue'],
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
plugins: [
new webpack.BannerPlugin('最终版权归aaa所有'),
new HtmlWebpackPlugin({
template: 'index.html'
})
]
}
dev.config.js文件:
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')
module.exports = webpackMerge(baseConfig, {
devServer: {
contentBase: './dist',
inline: true
}
})
prod.config.js文件:
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')
module.exports = webpackMerge(baseConfig, {
plugins: [
new UglifyjsWebpackPlugin()
]
})
之后就可以删除webpack.config.js,然后需要自己指定配置文件
"Scripts": {
...
"build": "webpack --config ./build/prod.config.js",
"dev": "webpack-dev-server --open --config ./build/dev.config.js"
}
为了把dist文件放到根目录下,修改base.config.js的path参数为../dist
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.js',
},

浙公网安备 33010602011771号