内容简介:新建一个文件夹运行以下命令安装最新版本或特定版本
Webpack 基础篇
基本概念
Webpack
是一个现代 JavaScript
应用程序的静态模块打包器。当 webpack
处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle
。
四个核心概念
- 入口(Entry): 构建
Webpack
内部依赖图的入口模块 - 输出(Output): 输出
Webpack
打包好的Bundles
- Loader: 加载器,
Webpack
原生只能解析JavaScript
文件,Loader
让webpack
拥有了加载和解析非JavaScript
文件的能力。 - 插件(Plugins): 扩展
Webpack
的功能,让Webpack
具有更多的灵活性。在Webpack
运行的生命周期中会广播出许多事件,Plugin
可以监听这些事件,在合适的时机通过Webpack
提供的API
改变输出结果。
Webpack 基础配置
初始化项目
新建一个文件夹 webpack-demo
,在该目录中使用 npm init -y
进行项目初始化。
mkdir webpack-demo && cd webpack-demo npm init -y
运行以下命令安装最新版本或特定版本
npm i -D webpack npm i -D webpack@<version>
如果你使用 webpack 4+
版本,你还需要安装 CLI
。
npm i -D webpack-cli
-
npm i -D
为npm install --save-dev
的缩写,安装一个用于开发环境的安装包 -
npm i -S
为npm install --save
的缩写,安装一个要打包到生产环境的安装包
现在安装的 webpack
版本号是:
├── webpack@4.42.1 └── webpack-cli@3.3.11
新建 src/index.js
文件:
// src/index.js class HelloComponent { constructor (content = '') { this.content = content; this.render(); } render () { const element = document.createElement('div'); element.innerHTML = this.content; document.body.appendChild(element); } } new HelloComponent('hello webpack');
现在可以直接执行 npx webpack
,默认是 production
模式。
也可以在 package.json
中的 scripts
里配置一个 build
命令,模式指定为 production
。
webpack
默认会将 ./src/index.js
作为入口文件,默认打包到 dist/main.js
。
// ... "scripts": { "build": "webpack --mode=production" } // ...
通过 npm run build
可以执行我们定义的命令,这是可以多了 dist/main.js
文件,这就是打包之后的 js
代码。
webpack 配置文件
上面例子中使用的是 webpack
的默认配置,下面我们来定义更加丰富的自定义配置。
根目录下新建 webpack.config.js
文件
const path = require('path'); module.exports = { mode: 'development', // 模式 entry: path.resolve(__dirname, 'src/index.js'), // 入口文件 output: { path: path.resolve(__dirname, 'dist'), // 输出目录 filename: 'bundle.js' // 输出文件名 } }
更改我们的 build
命令,指定 webpack
按照我们的配置文件来打包文件
"scripts": { "build": "webpack --config webpack.config.js" }
执行 npm run build
可以看到, dist
目录下新增了 bundle.js
文件。并且 bundle.js
是在开发模式下打包的,可以看到更多的信息。
html-webpack-plugin 插件
现在我们已经有了打包好的 js
文件了,需要添加个 html
文件来引入这个 js
文件在浏览器查看效果了。
在实际开发中,为了避免每次修改打包的 js
文件被浏览器缓存而看不到最新的代码,我们会给打包文件加上 hash
,相当于这个文件的版本号。这样每次修改后打包的 js
文件名都会不同,如果人工去修改 html
中的 js
文件名就太麻烦了,我们可以借助 html-webpack-plugin
插件来自动完成这些事情。
安装 html-webpack-plugin
npm i -D html-webpack-plugin
新建 public/index.html
文件,修改我们的 webpack.config.js
// webpack.config.js const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { //... plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, 'public/index.html'), // 指定模板文件,不指定会生成默认的 index.html 文件 filename: 'index.html' // 打包后的文件名 }) ] }
执行 npm run build
可以看到 dist
目录下新增了 index.html
文件,并且自动将打包好的 bundle.js
文件通过 script
标签引入了。
webpack-dev-server 开发工具
现在可以通过浏览器直接打开 dist/index.html
查看了,但是这样每次改完代码我们都需要手动 npm run build
一下,这样太麻烦了。
我们可以借助 webpack-dev-server
来解决这个问题。 webpack-dev-server
会提供了一个简单的 web
服务器,并且能够实时重新加载。
安装 webpack-dev-server
npm i -D webpack-dev-server
修改 package.json 文件
// package.json "scripts": { "dev": "webpack-dev-server --config webpack.config.js", "build": "webpack --config webpack.config.js" }
npm run dev
之后,默认会在 localhost:8080
下建立服务,通过访问这个地址可以访问到 dist
目录下的文件。
可以在 webpack.config.js
对 devServer
进行配置
// webpack.config.js module.exports = { // ... devServer: { contentBase: path.join(__dirname, 'dist'), port: '9000', // 指定端口,默认是8080 compress: true // 是否启用 gzip 压缩 } //... }
关于 webpack-dev-server
更多的配置可以 点击查看 。
mode
我们在 package.json
定义了两条命令,但是 mode
都为 development
。我们可以通过设置 process.env.NODE_ENV
的值来区分开发还是生产环境。
我们需要安装一下 cross-env
, 来实现跨平台设置 NODE_ENV
npm i -D cross-env
// package.json "scripts": { "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js", "build": "cross-env NODE_ENV=production webpack --config webpack.config.js" }
修改 webpack.config.js
// webpack.config.js const isProduction = process.env.NODE_ENV == 'production'; module.exports = { mode: isProduction ? 'production' : 'development', // 模式 // ... }
设置 mode
的不同值可以启用相应模式下的 webpack
内置的优化
选项 | 描述 |
---|---|
development |
会将 process.env.NODE_ENV 的值设为 development 。启用 NamedChunksPlugin 和 NamedModulesPlugin 。 |
production |
会将 process.env.NODE_ENV 的值设为 production 。启用 FlagDependencyUsagePlugin , FlagIncludedChunksPlugin , ModuleConcatenationPlugin , NoEmitOnErrorsPlugin , OccurrenceOrderPlugin , SideEffectsFlagPlugin 和 UglifyJsPlugin . |
用 babel 向后兼容 js 语法
现在我们的代码虽然已经完成了打包,但是并没有被转义为低版本的代码。我们需要通过 Babel
来将 ECMAScript 2015+
版本的代码转换为向后兼容的 JavaScript
语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
安装 babel-loader
npm i -D babel-loader
此外我们还需要安装以下依赖
npm i -D @babel/core @babel/preset-env @babel/plugin-transform-runtime npm i -S @babel/runtime @babel/runtime-corejs3
在 webpack.config.js
配置 babel-loader
// webpack.config.js module.exports = { // ... module: { rules: [ { test: /\.jsx?$/, use: ['babel-loader'], exclude: /node_modules/ // 排除 node_modules 目录 } ] } // ... }
建议给 loader
指定 include
或是 exclude
,排除一些不需要编译的目录可以提高编译效率,比如 node_modules
目录。
有两种方式配置 babel
-
通过
.babelrc
文件配置根目录下新建一个
.babelrc
文件,配置如下:
// .babelrc { "presets": ["@babel/preset-env"], "plugins": [ [ "@babel/plugin-transform-runtime", { "corejs": 3 } ] ] }
- 在
webpack
中配置babel
// webpack.config.js module.exports = { module: { rules: [ { test: /\.jsx?$/, use: { loader: 'babel-loader', options: { presets: ["@babel/preset-env"], plugins: [ [ "@babel/plugin-transform-runtime", { "corejs": 3 } ] ] } }, exclude: /node_modules/ } ] } }
通过执行 npm run dev
, 我们查看 http://localhost:9000/bundle.js
发现已经是转义之后的低版本代码了。
使用 source map
当 webpack
打包源代码时,会很难追踪到错误和警告在源代码中的原始位置。为了更容易地追踪错误和警告, JavaScript
提供了 source map
功能,将编译后的代码映射回原始源代码。
在开发环境中,可以设置 devtool
值为 inline-source-map
,生产环境设置为 none
或者 source-map
。
// webpack.config.js const isProduction = process.env.NODE_ENV == 'production'; module.exports = { // ... devtool: isProduction ? 'source-map' : 'inline-source-map', }
使用 source-map
最终会单独打包出一个 .map
文件,我们可以根据报错信息和 map
文件定位到源代码。
但是一般不会直接将 .map
文件部署到 CDN
,而是将 .map
文件传到错误监控系统,以便我们可以解析到出错的源码位置。
处理样式文件
webpack
只能处理 js
文件,如果要处理 css
需要借助 loader
。
如果是 .css
,我们需要的 loader
有: style-loader
、 css-loader
,考虑到兼容性问题,还需要 postcss-loader
、 autoprefixer
如果是 .less
, 还需要 less-loader
、 less
如果是 .sass
的话,还需要 sass-loader
、 node-sass
安装相应的依赖
npm i -D style-loader css-loader postcss-loader autoprefixer less-loader less sass-loader node-sass
webpack.config.js
添加 css
、 less
、 sass loader
// webpack.config.js module.exports = { // .. module: { rules: [ // ... { test: /\.(c|le)ss$/, use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'], exclude: /node_modules/ // 排除 node_modules 目录 }, { test: /\.sass$/, use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'], exclude: /node_modules/ // 排除 node_modules 目录 } ] } }
根目录新建 postcss.config.js
// postcss.config.js module.exports = { plugins: [ // 兼容浏览器,添加前缀 require('autoprefixer')({ overrideBrowserslist: [ "Android 4.1", "iOS 7.1", "Chrome > 31", "ff > 31", "ie >= 8" // 'last 10 versions', // 所有主流浏览器最近10版本用 ], grid: true }) ] }
配置完成,新建几个文件测试一下
/* src/index.css */ div { width: 200px; height: 100px; display: flex; }
// src/index.less @color: yellow; body { background: @color; display: flex; }
// src/index.sass $text-color: orange; div color: $text-color; display: flex;
再在入口文件中引入三个文件
// src/index.css import './index.css'; import './index.less'; import './index.sass';
我们可以看到样式生效并且 flex
也自动加上浏览器前缀了。
需要注意的是 loader
的执行顺序是从右向左执行的,执行顺序为:
less-loader
/ sass-loader
=> postcss-loader
=> css-loader
=> style-loader
-
less-loader
处理编译.less
文件,将其转为css
-
sass-loader
处理编译.sass
文件,将其转为css
-
postcss-loader
和autoprefixer
,自动生成浏览器兼容性前缀 -
css-loader
处理css
中的@import
、url(...)
等语句 -
style-loader
动态创建style
标签,将css
插入到head
中
处理图片、字体等媒体文件
我们可以使用 url-loader
或者 file-loader
来处理本地的资源文件。
file-loader
就是将文件在进行一些处理后(主要是处理文件名和路径、解析文件 url
),将文件移动到输出的目录中,同时在 require
文件的地方会返回文件的绝对路径。
url-loader
一般与 file-loader
搭配使用,功能与 file-loader
类似,如果文件小于限制的大小,则会返回 base64
编码。
需要同时安装 file-loader
和 url-loader
npm i -D file-loader url-loader
配置 webpack.config.js
// webpack.config.js module.exports = { // .. module: { rules: [ // ... { test: /\.(jpe?g|png|gif|webp|svg|eot|ttf|woff|woff2)$/i, use: [ { loader: 'url-loader', options: { limit: 10240, // 10K 资源大小小于 10K 时,将资源转换为 base64,超过 10K,将图片拷贝到 dist 目录 name: '[name]_[hash:6].[ext]', // 设置文件名,默认情况下,生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名 outputPath: 'assets', // 输出目录 esModule: false // 表示是否使用es6模块的导出,默认是启用的 } } ], exclude: /node_modules/ } ] } }
我们修改 src/index.sass
文件
// src/index.sass $text-color: orange; div color: $text-color; display: flex; background: url('../images/author.jpg');
修改了配置文件,我们重新 npm run dev 一下,可以看到图片地址已经被替换了
npm run build
可以看到 dist/assets
有这个文件
注意此时如果需要在 html
文件中引用这个图片需要这样写
<body> <img src="<%= require('../images/author.jpg') %>"> </body>
最终打包之后的路径是
打包前清空 dist 目录
我们修改文件打包之后,生成的 hash
值和之前 dist
中的不一样,会导致 dist
下的文件越来越多,所以我们需要在打包前先清空 dist
目录。
安装 clean-webpack-plugin
npm i -D clean-webpack-plugin
// webpack.config.js const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { //... plugins: [ // ... new CleanWebpackPlugin() ] }
这样每次打包前就会自动清除 dist
目录下的文件了。
最后
通过上面的实践,我们对 webpack
的基础配置有了一个初步的了解。本文所有代码可以 查看github 。
后续将会继续推出 webpack
系列的其他内容哦~
喜欢本文的话点个赞吧~
更多精彩内容,欢迎关注微信公众号~
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ACM国际大学生程序设计竞赛题解
赵端阳//袁鹤 / 电子工业 / 2010-7 / 39.00元
随着各大专院校参加ACM/ICPC热情的高涨,迫切需要有关介绍ACM国际大学生程序设计竞赛题解的书籍。《ACM国际大学生程序设计竞赛题解(2)》根据浙江大学在线题库的部分题目,经过分类、筛选、汇编,并进行了解答(个别特别简单或者特别复杂的题目未选择),比较详细地分析和深入浅出地讲解了解题的方法和用到的算法。题目的类型包括基础编程、模拟、字符串处理、搜索、动态规划、回溯、图论、几何和数学题。 ......一起来看看 《ACM国际大学生程序设计竞赛题解》 这本书的介绍吧!