目录
一 、webpack是什么?
Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。(本文以webpack4为准)
二、 安装webpack
首先确保本地环境支持node.js,再使用npm安装webpack,如果觉得npm安装速度慢,可使用淘宝镜像及其命令cnpm
- 全局安装webpack命令行如下
-
npm install webpack -g
- 项目安装webpack命令行如下
-
npm install webpack --save-dev
三、webpack基本打包命令
1. webpack起步
- 新建一个项目目录webpack,在目录下添加main.js文件,代码如下:
document.write("哈哈哈哈哈哈哈哈哈哈");
- 在webpack目录下添加index.html文件,代码如下:
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript" src="bundle.js" charset="utf-8"></script>
</body>
</html>
- 接下来使用webpack命令来打包,命令如下
webpack main.js bundle.js
- 执行以上命令会编译main.js文件并生成bundle.js文件,打开index.html,会显示“哈哈哈哈哈哈哈哈哈哈”
2. webpack打包js
- 新建项目demo01,在demo01底下新建文件夹vendor,在vendor文件夹底下新建sum.js文件,使用ES6模块导出,代码如下
export default function(a, b) {
return a + b;
}
- 在demo01底下新建app.js文件,作为项目的入口文件,代码如下
/**
* webpack支持ES6、CommonJs和AMD规范
*/
// ES6
import sum from "./vendor/sum";
console.log("sum(1, 2) = ", sum(1, 2));
- 在demo01文件夹底下新建webpack.config.js文件,进行打包配置,代码如下:
/**
* 必须使用CommonJs规范
* 更多高级用法:https://www.webpackjs.com/concepts/output/
*/
const path = require("path");
module.exports = {
entry: {
app: "./app.js"
},
output: {
publicPath: __dirname + "/dist/", // js引用路径或者CDN地址
path: path.resolve(__dirname, "dist"), // 打包文件的输出目录
filename: "bundle.js"
}
};
- 怎么运行呢,首先,得安装webpack,具体安装命令见上文,再使用npm init -y生成package.json文件,配置script,代码如下,再使用npm run build 进行打包。最后项目底下会生成一个文件夹dist,文件夹里有打包后的文件bundle.js,至此打包js完成。
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"webpack-cli": "^4.1.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "",
"license": "ISC"
}
- 打包后的目录结构
3. webpack编译es6
- 说到编译ES6,就不得不提到和babel相关的技术生态,具体情况如下:
babel-loader: 负责 es6 语法转化
babel-preset-env: 包含 es6、7 等版本的语法转化规则
babel-polyfill: es6 内置方法和函数转化垫片
babel-plugin-transform-runtime: 避免 polyfill 污染全局变量
这里需要注意的是:babel-loader和babel-polyfill,前者负责语法转化,比如:箭头函数啥的,后者负责内置方法和函数,比如 new Set() - 所以webpack要编译ES6,第一步得安装相关的库,这次,package.json文件配置如下:(记得npm install)
{
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"webpack": "^4.15.1"
},
"dependencies": {
"babel-polyfill": "^6.26.0",
"babel-runtime": "^6.26.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
}
}
- 在webpack中使用babel,babel的相关配置,单独写在.babelrc文件中,相关配置如下:
{
"presets": [
[
"env",
{
"targets": {
"browsers": ["last 2 versions"]
}
}
]
],
"plugins": ["transform-runtime"]
}
- 在webpack配置文件中,关于babel的调用需要写在module模块中。对于相关的匹配规则,除了匹配js结尾的文件,还应该去除node_module文件夹下的第三方库。
/* 相关步骤:
* 1 安装相关库
* 2 在webpack中使用babel,babel的相关配置,单独写在.babelrc中
* 3 在webpack配置文件中,关于Babel的调用需要写在module模块中
* 4 babel-polyfill它需要在我们项目的入口文件中被引入(这里使用这种),或者在webpack.config.js中配置。
*/
module.exports = {
entry: {
app: "./app.js"
},
output: {
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.js$/,
// 这里应该除去node_modules文件夹下的第三方库文件
exclude: /(node_modules)/,
use: {
loader: "babel-loader" // 转化需要的loader
// options选项配置在: .babelrc
// options: {
// ...
// }
}
}
]
}
};
- 项目入口文件app.js,在这里我们要引入babel-polyfill,具体代码如下:
import "babel-polyfill";
let func = () => {};
const NUM = 45;
let arr = [1, 2, 4];
let arrB = arr.map(item => item * 2);
console.log(arrB.includes(8));
console.log("new Set(arrB) is ", new Set(arrB));
- 安装完webpack之后,使用npm run build进行打包,会生成dist文件夹,及bundle.js,到此es编译打包结束。可以在html文件中引用打包后的文件,打开html文件即可查看效果。打包后的目录结构如下图所示:
4. webpack提取公共代码(多页面应用)
- 首先,先在src文件夹下创建 pageA.js 和 pageB.js分别作为两个入口文件。同时,这两个入口文件同时引用subPageA.js,subPageB.js,而subPageA.js,subPageB.js又同时引用module.js文件。
项目基本结构如下: - module.js代码如下:
export default "module";
- subPageA.js:导入公共模块module
import "./module";
export default "subPageA";
- subPageB.js:导入公共模块module
import "./module";
export default "subPageB";
- 最后封装入口文件,pageA.js
import "./subPageA";
import "./subPageB";
import * as _ from "lodash";
console.log("At page 'B' :", _);
export default "pageA";
pageB.js:
import "./subPageA";
import "./subPageB";
import * as _ from "lodash";
console.log("At page 'A' :", _);
export default "pageB";
- 然后编写package.js配置文件,代码如下:
{
"devDependencies": {
"webpack": "^4.15.1"
},
"dependencies": {
"lodash": "^4.17.10"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
}
}
- 最后编写webpack配置文件,进行打包配置,具体代码如下:
const webpack = require("webpack");
const path = require("path");
module.exports = {
// 多页面应用
entry: {
pageA: "./src/pageA.js",
pageB: "./src/pageB.js"
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js",
chunkFilename: "[name].chunk.js"
},
// 着重看这个配置,将需要打包的代码放在 cacheGroups属性中
optimization: {
splitChunks: {
cacheGroups: {
// 注意: priority属性
// 其次: 打包业务中公共代码,每个键值对就是被打包的一部分,
// 针对第三方库通过设置priority来让其先被打包提取,最后再提取剩余代码
common: {
name: "common",
chunks: "all",
minSize: 1,
priority: 0
},
// 首先: 打包node_modules中的文件
vendor: {
name: "vendor",
test: /[\\/]node_modules[\\/]/,
chunks: "all",
priority: 10
// enforce: true
}
}
}
}
};
- npm install 之后,使用npm run build 进行打包,打包后的项目目录结构如下图所示:
5. webpack单页面解决方案–代码分割和懒加载
- 针对单页应用提取公共代码需要通过代码分割和懒加载
- 代码分割和懒加载是通过代码写法来实现(见下文page.js代码),并不是通过webpack配置来实现
- 此demo的package.json代码如下:
{
"devDependencies": {
"webpack": "^4.15.1"
},
"dependencies": {
"lodash": "^4.17.10"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
}
}
- 公共模块module.js:
export default "module";
- subPageA.js:
import "./module";
console.log("I'm subPageA");
export default "subPageA";
- subPageB.js:
import "./module";
console.log("I'm subPageB");
export default "subPageB";
- page.js:重点代码在这里
/**
* requir.ensure(): 只是加载并不执行
* import(): 加载并且自动执行
*/
import(/* webpackChunkName: 'subPageA'*/ "./subPageA").then(function(subPageA) {
console.log(subPageA);
});
import(/* webpackChunkName: 'subPageB'*/ "./subPageB").then(function(subPageB) {
console.log(subPageB);
});
import(/* webpackChunkName: 'lodash'*/ "lodash").then(function(_) {
console.log(_.join(["1", "2"]));
});
export default "page";
- webpack配置文件如下:
const webpack = require("webpack");
const path = require("path");
module.exports = {
entry: {
page: "./src/page.js" //
},
output: {
publicPath: __dirname + "/dist/",
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js",
chunkFilename: "[name].chunk.js"
}
};
- 使用npm run build命令进行打包,打包后的项目目录如下:
6. webpack处理CSS
- 项目依赖如下:
{
"devDependencies": {
"css-loader": "^1.0.0",
"file-loader": "^1.1.11",
"style-loader": "^0.21.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
}
}
- base.css:
*,
body {
margin: 0;
padding: 0;
}
html {
background: red;
}
- app.js:
let clicked = false;
window.addEventListener("click", function() {
if (!clicked) {
// 加载css样式文件
import("./css/base.css");
}
});
// style-loader/useable:
// 可以直接使用use()或者unuse()方法来加载/卸载CSS样式
//
// import base from "./css/base.css";
// var flag = false;
// setInterval(function() {
// if (flag) {
// base.unuse();
// } else {
// base.use();
// }
// flag = !flag;
// }, 500);
- css.transform.js:
// transform 选项是在import css样式后执行的
module.exports = function(css) {
console.log(css);
return window.innerWidth < 1000 ? css.replace("red", "green") : css;
};
- webpack配置文件如下
const path = require("path");
module.exports = {
entry: {
app: "./src/app.js"
},
output: {
publicPath: __dirname + "/dist/",
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
test: /\.css$/,
// css处理为style标签
use: [
{
loader: "style-loader",
options: {
singleton: true,
transform: "./css.transform.js"
}
},
{
loader: "css-loader",
options: {
minimize: true
}
}
]
// css处理为link标签
// use: [
// {
// loader: "style-loader/url"
// },
// {
// loader: "file-loader"
// }
// ]
// css卸载和加载样式(use与unuse方法)
// use: [
// {
// loader: "style-loader/useable"
// },
// {
// loader: "css-loader"
// }
// ]
}
]
}
};
- 使用npm run build命令打包,项目打包后的目录如下:
7. webpack处理SCSS
- 项目所需依赖如下:
{
"devDependencies": {
"css-loader": "^1.0.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"node-sass": "^4.9.2",
"sass-loader": "^7.0.3",
"style-loader": "^0.21.0",
"webpack": "^4.16.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
}
}
- base.scss:
$bgColor: red !default;
*,
body {
margin: 0;
padding: 0;
}
html {
background-color: $bgColor;
}
- 在app.js中导入scss文件:
import "./scss/base.scss";
- 配置webpack:注意loader顺序,不能颠倒,只有通过css-loader处理css之后才能通过style-loader,指定多个loader时的顺序是固定的,而调用loader的顺序是从前往后解析的。
const path = require("path");
module.exports = {
entry: {
app: "./src/app.js"
},
output: {
publicPath: __dirname + "/dist/",
path: path.resolve(__dirname, "dist"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
test: /\.scss$/,
// 注意 loader 顺序,不能颠倒
use: [
{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
},
{
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
},
{
loader: "sass-loader" // 将 Sass 编译成 CSS
}
]
}
]
}
};
- 使用npm run build打包,打包后的文件结构如下: