Webpack速成II
webpack 有四个核心部分
- entry 规定入口文件,一个或者多个
- output 规定输出文件的位置
- loader 各个类型的转换工具
- plugin 打包过程中各种自定义功能的插件
基础配置
初始化环境
新建 src 目录并在其中新建 index.js ,随便写点 console.log('index js') 。然后根目录创建 webpack.config.js ,内容如下
const path = require('path') module.exports = { // mode 可选 development 或 production ,默认为后者 // production 会默认压缩代码并进行其他优化(如 tree shaking) mode: 'development', entry: path.join(__dirname, 'src', 'index'), output: { filename: 'bundle.js', path: path.join(__dirname, 'dist') } }然后增加 package.json 的 scripts
"scripts": { "build": "webpack" },
打包上线build
使用 webpack 需要两个最基本的功能: 第一,开发的代码运行一下看看是否有效;
第二,开发完毕了将代码打包出来。
这两个操作的需求、配置都是完全不一样的。例如,运行代码时不需要压缩以便 debug ,而打包代码时就需要压缩以减少文件体积。因此,最好还是把他们区分开
dev——本地运行 build——打包上线
dev——本地运行 build——打包上线
打包上线的例子:
首先,安装 npm i webpack-merge -D ,然后根目录新建 build 目录,其中新建了三个文件:
1.webpack.common.js 公共的配置
const path = require('path') const srcPath = path.join(__dirname, '..', 'src') const distPath = path.join(__dirname, '..', 'dist') module.exports = { entry: path.join(srcPath, 'index') }2.webpack.dev.js 运行代码的配置
const path = require('path') const webpackCommonConf = require('./webpack.common.js') const { smart } = require('webpack-merge') const srcPath = path.join(__dirname, '..', 'src') const distPath = path.join(__dirname, '..', 'dist') module.exports = smart(webpackCommonConf, { mode: 'development' })3.webpack.prod.js 打包代码的配置
const path = require('path') const webpackCommonConf = require('./webpack.common.js') const { smart } = require('webpack-merge') const srcPath = path.join(__dirname, '..', 'src') const distPath = path.join(__dirname, '..', 'dist') module.exports = smart(webpackCommonConf, { mode: 'production', output: { filename: 'bundle.[contentHash:8].js', // 打包代码时,加上 hash 戳 path: distPath, // publicPath: 'http://cdn.abc.com' // 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到 } })在这个例子中,我们要打包上线,因此,修改package.json 中的 scripts:
"scripts": { "build": "webpack --config build/webpack.prod.js" },
JS模块化
webpack 默认支持 js 各种模块化,如常见的 commonJS 和 ES6 Module 。但是推荐使用 ES6 Module ,因为 production 模式下,ES6 Module 会默认触发 tree shaking ,而 commonJS 则没有这个福利。究其原因,ES6 Module 是静态引用,在编译时即可确定依赖关系,而 commonJS 是动态引用。
不过使用 ES6 Module 时,ES6 的解构赋值语法这里有一个坑,例如 index.js 中有一行 import {fn, name} from './a.js' ,此时 a.js 中有以下几种写法,大家要注意!
// 正确写法一 export function fn() { console.log('fn') } export const name = 'b' // 正确写法二 function fn() { console.log('fn') } const name = 'b' export { fn, name }错误写法:
// 错误写法 function fn() { console.log('fn') } export default { fn, name: 'b' }
本地服务dev
启动本地服务,肯定需要一个 html 页面作为载体,新建一个 src/index.html 并初始化内容
<!DOCTYPE html> <html> <head><title>Document</title></head> <body> <p>this is index html</p> </body> </html>但是为了使用html文件,还要安装 npm i html-webpack-plugin -D ,然后配置 build/webpack.common.js ,因为无论 dev 还是 prod 都需要打包 html 文件。
plugins: [ new HtmlWebpackPlugin({ template: path.join(srcPath, 'index.html'), filename: 'index.html' }) ]此时就可以启动服务了
首先安装 npm i webpack-dev-server -D ,然后打开 build/webpack.dev.js配置serve。
只有运行代码才需要本地 server ,打包代码时不需要。
devServer: { port: 3000, progress: true, // 显示打包的进度条 contentBase: distPath, // 根目录 open: true, // 自动打开浏览器 compress: true // 启动 gzip 压缩 }
还需要打开package.json 修改 scripts ,增加 "dev": "webpack-dev-server --config build/webpack.dev.js"
解决跨域
实际开发中,server 端提供的端口地址和前端可能不同,导致 ajax 收到跨域限制。使用 webpack-dev-server 可配置代理,解决跨域问题。如有需要,在 build/webpack.dev.js 中增加如下配置:
devServer: { // 设置代理 proxy: { // 将本地 /api/xxx 代理到 localhost:3000/api/xxx '/api': 'http://localhost:3000', // 将本地 /api2/xxx 代理到 localhost:3000/xxx '/api2': { target: 'http://localhost:3000', pathRewrite: { '/api2': '' } } }
处理ES6
babel
由于现在浏览器还不能保证完全支持 ES6 ,将 ES6 编译为 ES5 ,需要借助 babel 这个神器。
安装 babel npm i babel-loader @babel/core @babel/preset-env -D ,然后修改 build/webpack.common.js 配置
安装 babel npm i babel-loader @babel/core @babel/preset-env -D ,然后修改 build/webpack.common.js 配置
module: { rules: [ { test: /\.js$/, loader: ['babel-loader'], include: srcPath, exclude: /node_modules/ }, ] },还要根目录下新建一个 .babelrc json 文件,内容如下:
{ "presets": ["@babel/preset-env"], "plugins": [] }配置完了会达到什么什么效果呢?
我们在 src/index.js 中加入一行 ES6 代码,如箭头函数 const fn = () => { console.log('this is fn') } 。
然后重新运行 npm run dev,可以看到浏览器中加载的 js 中,这个函数已经被编译为 function 形式。
使用高级特性
babel 可以解析 ES6 大部分语法特性,但是无法解析 class 、静态属性、块级作用域,还有很多大于 ES6 版本的语法特性,如装饰器。因此,想要把日常开发中的 ES6 代码全部转换为 ES5 ,还需要借助很多 babel 插件。
安装 npm i @babel/plugin-proposal-class-properties @babel/plugin-transform-block-scoping @babel/plugin-transform-classes -D ,然后配置 .babelrc
Source map
{ "presets": ["@babel/preset-env"], "plugins": [ "@babel/plugin-proposal-class-properties", "@babel/plugin-transform-block-scoping", "@babel/plugin-transform-classes" ] }
source map 用于反解析压缩代码中错误的行列信息,
但dev 时代码没有压缩,用不到 source map ,因此要配置在build/webpack.prod.js
// webpack 中 source map 的可选项,是情况选择一种: // devtool: 'source-map' // 1. 生成独立的 source map 文件 // devtool: 'eval-source-map' // 2. 同 1 ,但不会产生独立的文件,而是集成到打包出来的 js 文件中 // devtool: 'cheap-module-source-map' // 3. 生成单独的 source map 文件,但没有列信息(因此文件体积较小) devtool: 'cheap-module-eval-source-map' // 4. 同 3 ,但不会产生独立的文件,集成到打包出来的 js 文件中生产环境下推荐使用 1 或者 3 ,即生成独立的 map 文件。
处理样式
在 webpack 看来,不仅仅是 js ,其他的文件也是一个一个的模块,通过相应的 loader 进行解析并最终产出。
处理css
安装必要插件 npm i style-loader css-loader -D ,然后配置 build/webpack.common.js
module: { rules: [ { /* js loader */ }, { test: /\.css$/, loader: ['style-loader', 'css-loader'] // loader 的执行顺序是:从后往前 } ] },处理less
安装必要插件 npm i less less-loader -D ,然后配置 build/webpack.common.js
{ test: /\.less$/, loader: ['style-loader', 'css-loader', 'less-loader'] // 增加 'less-loader' ,注意顺序 }
作者:双越
链接:https://www.imooc.com/article/287156
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作
作者:双越
链接:https://www.imooc.com/article/287156
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作
作者:双越
链接:https://www.imooc.com/article/287156
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作
作者:双越
链接:https://www.imooc.com/article/287156
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作