内容简介:使用包的版本每个章节对应一个demo进入项目目录,运行 npm init来创建项目
使用包的版本
webpack ->4.3.0 babel-loader ->8.0.5 npm ->6.4.1 webpack-cli ->3.3.1 复制代码
每个章节对应一个demo
一、初始化项目
进入项目目录,运行 npm init来创建项目
npm init 复制代码
终端输入完成后会自动创建一个package.json的文件。
{ "name": "demo1", "version": "1.0.0", "description": "webpack-demo", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack app.js" }, "keywords": [ "demo" ], "author": "cmf", "license": "ISC", "devDependencies": {} } 复制代码
运行命令,引入webpack和webpack-cli,安装webpack-cli是为了在项目里面运行webpack命令。
npm i webpack webpack-cli -D 复制代码
手动创建webpack.config.js。
touch webpack.config.js 复制代码
在终端里面通过 npx 运行webpack命令无法进行复杂配置。所以创建webpack.config.js是为了后面的复杂配置。 新建app.js、index.html、view文件夹、view文件夹里面创建dom.js。
mkdir view touch app.js cd view touch app.js 复制代码
代码内容详见 demo1 配置 webpack.config.js
打包方式有两种
- 通过npx命令
npx webpack 复制代码
- 通过配置package.json的script对象。
"scripts": { "build": "webpack" }, 复制代码
这两种方式都会自动寻找项目里面的webpack包进行打包,并且webpack会根据webpack.config.js的配置规则进行打包。
二、配置开发和生产环境
- 开发环境特点
- 可视化
- 本地服务
- 可以快速找到代码错误
- 热更新
- 生产环境特点
- 代码压缩
- 代码拆包
- 快速响应
下载插件包
npm i cross-env html-webpack-plugin webpack-dev-server -D 复制代码
cross-env 跨平台的解决了环境变量和参数的命令配置。
html-webpack-plugin 打包生成HTML的插件。
webpack-dev-server 创建开发服务器。功能强大,接口转发、热更新等。
文件更改
新建index.html、help.js
touch index.html touch help.js 复制代码
index.html 模板文件
<head> <title>demo2</title> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> </head> <body> <div id="app"></div> </body> 复制代码
help.js 封装的一些方法。
module.exports.getMode = function() { return process.env.NODE_ENV === 'development'?'development':'production' }; 复制代码
配置更改
webpack-dev-server其他配置请参考官方文档。
mode模式。默认值是production。 告知 webpack 使用相应模式的内置优化。是 webpack4新增的属性。比如mode是production,webpack会默认添加一些打包插件比如:NoEmitOnErrorsPlugin。可以节省很多配置。
命令配置
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "cross-env NODE_ENV=production webpack", "dev": "cross-env NODE_ENV=development webpack-dev-server" }, 复制代码
cross-env NODE_ENV=production设置环境变量信息
npm run dev 复制代码
自动打开浏览器,会把app.js里面的内容自动注入到index.html里面。
三、模板解析与外部扩展
代码内容详见 demo3
外部扩展(externals)
externals防止将某些 import 的包是从外部获取依赖不是从node_modules里面获取的。
例如我们在app.js里面
// app.js import Vue from 'Vue'; 复制代码
index.html
<head> <title>demo4</title> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> </head> 复制代码
webpack.config.js
externals:{ //外部扩展 'Vue':'window.Vue' }, 复制代码
现在app.js 里面引入的 Vue 是从cdn里面引入的,而不是从 node_modules 包里面引入的。 这样做的好处:
- 提高打包效率。
- 类似于使用Vue这样的框架,使用的版本是一般是固定不变的。所以cdn引入的时候相当于模块化拆包。用户刷新浏览器和代码重新打包发版都不会再次请求Vue的代码,提高用户体验。
模板解析(resolve)
resolve开发者可以自定义解析规则。
-
resolve.modules 自定义依赖包的路径。参数是array,可以是相对目录也可以是绝对目录。默认是 [path.resolve(process.cwd(),'node_modules')] 。当前命令的目录下面的node_modules文件夹。
如果一个大的项目里面有很多子项目,每个子项目没必要都安装依赖包,所以可以在各个子项目里面通过配置resolve.modules指向母项目的node_modules包。
-
resolve.modules 自定义引入模块时可以不带扩展名。参数是array。默认['.js','.json']
extensions:['.js','.vue','.json','.css','.less'], 复制代码
代码里面
import 'view/dom' 复制代码
会自动找到dom.js
-
resolve.alias 自定义路径别名。参数是object。
alias:{ '@': path.resolve(__dirname, './src') }, // __dirname 当前文件的目录地址。 复制代码
在代码里可以使用@符号指向src目录。
import '@/view/dom.js'; 复制代码
好处:在很深的代码层里面如果想引入顶层的某个js文件。不需要写很多'../../../'去找文件,提高开发效率。
resolve里面有很多的自定义解析规则。有时间都可以尝试一下。
四、生产与开发环境分开打包
代码内容详见 demo4
虽然在webpack4里面提供了mode属性来分别打包开发和生产环境,各自提供不同的插件。但是如果 clean-webpack-plugin 插件想在生产环境使用在开发环境不使用,就需要每次手动更改配置,这样做很不合理,容易出错。
可以使用
- 指定配置文件。
webpack --config 配置文件 复制代码
- 合并公共的配置 webpack-merge
具体操作
新增依赖包
npm i webpack-merge -D 复制代码
新增文件
新建build文件夹
mkdir build cd build touch weboack.build.conf.js、webpack.base.conf.js、webpack.dev.conf.js config.js help.js 复制代码
help.js储层公共方法
var path = require('path'); module.exports.getMode = function() { return process.env.NODE_ENV === 'development'?'development':'production' }; module.exports.resolve = function(p){ return path.resolve(process.cwd(),p); } 复制代码
config.js开发与生产的配置信息
module.exports = { dev: { mode: 'development', publicPath: '/', devServer: { port: '8899', proxy: { '/test/shortRent': { target: 'http:"//www.baidu.com', changeOrigin: true, pathRewrite: { '^/test/shortRent': '/evcard-evrental' } }, }, }, }, build: { mode: 'production', publicPath: './', assetsRoot: 'you-app' } } 复制代码
webpack.base.conf.js开发与生产相同的webpack配置
var path = require('path'); var help = require('./help.js'); var config = require('./config.js'); var htmlWebpackPlugin = require('html-webpack-plugin'); var mode = help.getMode(); module.exports={ entry:{ app:help.resolve('./app.js') }, output:{ }, resolve:{ // 解析 alias:{ '@': help.resolve('./src') }, extensions:['.js','.vue','.json','.css','.less'], modules: ["./node_modules"] }, externals:{ //外部扩展 'Vue':'window.Vue' }, plugins:[ new htmlWebpackPlugin({ filename:'index.html', template:'./index.html', inject:true, }) ], } 复制代码
webpack.dev.conf.js开发环境的webpack配置
var merge = require("webpack-merge"); var webpackConfigBase = require('./webpack.base.conf'); var help = require('./help.js'); var config = require('./config.js'); module.exports=merge(webpackConfigBase,{ mode: config.dev.mode, output:{ filename:help.assetsPath('js/[name].js'), publicPath:config.dev.publicPath }, devServer:config.dev.devServer }) 复制代码
webpack.build.conf.js生产环境的webpack配置
var cleanWebpackPlugin = require('clean-webpack-plugin'); var merge = require("webpack-merge"); var help = require('./help.js'); var webpackConfigBase = require('./webpack.base.conf.js'); var config = require('./config.js'); module.exports=merge(webpackConfigBase,{ mode: config.build.mode, output:{ filename:'assets/js/[name].[hash].js', publicPath:config.build.publicPath, path:help.resolve(config.build.assetsRoot), }, plugins:[ new cleanWebpackPlugin() ] }) 复制代码
命令修改
"scripts": { "build": "cross-env NODE_ENV=production webpack --config build/weboack.build.conf.js", "dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.conf.js" }, 复制代码
五、解析转译JS
代码内容详见 demo5
loaders
loader 用来解析文件转译成浏览器可以识别的文件。如.less、.vue、.jsx等这些文件浏览器是不能正常转译的,loaders的作用就是充当着'翻译'的作用。
babel-loader
我们在开发的时候都使用es6的语法去编写代码,但是有些浏览器不支持es6的代码就需要将es6转译成浏览器可以读懂的es5的代码。babel-loader的作用就是'翻译'es6代码。
基础配置
安装babel-loader。参照官方的安装方式,打开官网选择webpack的安装方式。
安装依赖
npm install --save-dev babel-loader @babel/core npm install @babel/preset-env --save-dev 复制代码
babel-loader @babel/core 是核心插件
preset-env 编译方式
配置规则
module: { rules: [ { test: /\.js$/, // 正则匹配,所有的.js文件都使用这个规则进行编译 exclude: /node_modules/, // 排除的文件夹。这个文件夹里面的的文件不进行转译 loader: "babel-loader", // 转译的插件 options: { // 转译的规则 presets: [ //转译器配置 [ "@babel/preset-env" ] ], plugins: [] // 转译插件配置 } }, ] } 复制代码
plugins(转译插件)。转译插件是用来转译单一功能的插件,比如transform-es2015-arrow-functions,这个插件只负责转译es2015新增的箭头函数。
presets(转译器)。转译器是一系列转译插件的集合。比如babel-preset-es2015就包含了es2015新增语法的所有转译插件,比如包含transform-es2015-arrow-functions(es2015箭头函数转译插件)、transform-es2015-classes(es2015 class类转译插件)等。转译器分为语法转译器和补丁转译器。详解
在app.js里面写es6的代码
const s = new Set([1, 2, 3, 4, 5, 3, 2, 16, 7, 83, 21, 2, 1]); var w = Object.assign({}, { w: 1, e: 4 }) console.log(w); console.log([...s]); function pro(v) { return new Promise((resolve) => { if (v) { resolve('真11') } else { resolve('假22') } }) } pro(true).then(res=>{ console.log(res) }) 复制代码
运行命令
npm run build 复制代码
打开打包后的app.js只有1.7kb。
promise里面的箭头函数已经被转译成了普通函数。
似乎看起来已经已经成功了。
npm run dev 复制代码在打包后的js全局搜索 promose ,代码里面只有一处。没有其他的代码来'翻译' promise
,这在低版本的浏览器里面是不行的,所以需要继续'翻译'。
垫片配置
Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转码。
所以还需要配置。 在babel@7.4以前使用@babel/polyfill为当前环境提供一个垫片。所谓垫片也就是垫平不同浏览器或者不同环境下的差异。
但是babel@7.4及以后这个垫片被废弃了。
babel-polyfill 等同于 regenerator runtime + core-js
官方建议使用
import "core-js/stable"; import "regenerator-runtime/runtime"; 复制代码
来代替@babel/polyfill。
- regenerator:提供对 generator 支持,如果应用代码中用到generator、async函数的话。
- core-js:提供 es(6-8) 新的特性。
core-js 在安装@babel/preset-env的时候已经安装好了。
npm i regenerator-runtime -D 复制代码
在app.js里面引入
import "core-js/stable"; import "regenerator-runtime/runtime"; 复制代码
运行命令
npm run build 复制代码
打包后的app.js有113kb。多出来了100多kb的代码。
打开打包后的js,搜索 promise一共有26处,这里面对promise的代码进行了'翻译'。
但代码相比以前也太大了。把所有转译es的代码都打包了。
优化
useBuiltIns 这个配置属性可以解决这个问题。官方文档的配置其实是babel@7.4以前的写法,这也造成了我懵逼了两天。
属性值 "usage" | "entry" | false, 默认是 false。
useBuiltIns: 'entry'其实和import "core-js/stable"; import "regenerator-runtime/runtime";效果是一样的,表示把所有的转译代码都注入到打包的代码里面。但是还是需要在代码里面引入这两个插件。
useBuiltIns: 'usage'表示把代码里面需要用到的转译代码注入到打包的代码里面。就不需要引入core-js/stable了。但是regenerator-runtime/runtime还是需要继续引入。
{ test: /\.js$/, // 正则匹配,所有的.js文件都使用这个规则进行编译 exclude: /node_modules/, // 排除的文件夹。这个文件夹里面的的文件不进行转译 loader: "babel-loader", // 转译的插件 options: { // 转译的规则 presets: [ //转译器配置 [ "@babel/preset-env", { useBuiltIns: "usage" } ] ], plugins: [] // 转译插件配置 } }, 复制代码
运行打包命令
npm run build 复制代码
打包报错了
根据preset-env 的文档说明还需要配置 corejs 。作用是代替引入 core-js/stable。
{ test: /\.js$/, // 正则匹配,所有的.js文件都使用这个规则进行编译 exclude: /node_modules/, // 排除的文件夹。这个文件夹里面的的文件不进行转译 loader: "babel-loader", // 转译的插件 options: { // 转译的规则 presets: [ //转译器配置 [ "@babel/preset-env", { useBuiltIns: "usage", corejs: 3 } ] ], plugins: [] // 转译插件配置 } }, 复制代码
运行打包命令
npm run build 复制代码
只有33kb。
打包的文件中有21个promise。
这样做的好处就是使用哪种es语法就引入哪种转译器,避免代码过大。为什么还需要继续引入regenerator-runtime/runtime呢?因为它的代码太少了,@babel/preset-env没有像corejs一样进行配置。如果不引入async、await就不能使用了。
babel-loader还有很多配置很多坑,遇到就查文档或者google吧。
六、样式loader与样式HMR
代码内容详见 demo6
样式loader
样式loader,这些都是官方提供的样式loader。
- style-loader 将js里面引入的css文件,解析成css样式并且添加到style标签里面。
- css-loader 解析css里面的@import引入的样式。
- less-loader sass-loader stylus-loader 都是解析css扩展语言。
- postcss-loader 为css3的代码自动添加前缀。
基础配置
比如 使用less作为样式语法。 首先安装style-loader css-loader。
npm i style-loader css-loader -D 复制代码
less-loader文档里面显示需要安装
npm install --save-dev less-loader less 复制代码
按照官方的配置进行rules配置。
编写base.less文件
body{ color: lawngreen; } .logo{ background: #f60; height: 400px; width: 400px; background-repeat: no-repeat; transition: all 1s; display: flex; } .logo:hover{ height: 600px; width: 600px; transform: translateY(60px); } 复制代码
在app.js 里面引入
import './src/assets/css/base.less'; 复制代码
运行命令
npm run dev 复制代码
自动添加css3浏览器前缀
less文件里面的transition和transform都是css3的样式,如果想自动的生成带前缀的代码则需要postcss-loader,也需要postcss-loader的一个插件 autoprefixer
安装依赖
npm i autoprefixer postcss-loader -D 复制代码
更改配置
{ loader: "postcss-loader", options: { plugins: [ require("autoprefixer")({ browsers: [ 'last 10 Chrome versions', 'last 5 Firefox versions', 'Safari >= 6', 'ie> 8' ] }) ] } }, 复制代码
browsers配置表示按照 大于ie8,Safari6,最后10个Chrome版本的规则进行编译。
npm run dev 复制代码
css3的代码都进行了前缀编码。
importLoaders
home.less里面的代码并没有进行css3的转化。这时我们需要配置在 css-loader 中使用importLoaders 属性。
将importLoaders设置为2因为,css-loader前面需要执行postcss-loader和less-loader。
生产环境配置
之前一直运行的是开发环境,我们运行一下生产打包命令
npm run build 复制代码
打包后并没有css文件。 把代码放入服务器或者使用 http-server 起一个本地的服务器。
这时我们需要引入 mini-css-extract-plugin 进行css代码的抽离,以及打包插件 optimize-css-assets-webpack-plugin 在打包的时候进行css代码压缩。
npm i mini-css-extract-plugin optimize-css-assets-webpack-plugin -D 复制代码
按照官方的语法进行配置
npm run build 复制代码
css的代码已经被抽离了并且压缩了。
样式HMR
查看官网有关于HMR解释。
模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。
按照官方的实例。 首先更改devServer的配置,设置hot属性为true。
因为设置模块热加载是开发环境需要的。所以更改webpack.dev.conf.js的配置。
plugins:[ new webpack.HotModuleReplacementPlugin() ] 复制代码
由于 mini-css-extract-plugin 不支持HMR,所以在开发环境继续使用 style-loader 。 现在css的HMR已经配置好了。
文件解析。
代码内容详见 demo7
文件解析需要用到的loaders。
使用url-loader作为文件解析的loader。file-loader是一种'搬运工'的loader,将代码中需要的文件'搬运'到合适的地方, url-loader在搬运的基础上可以在代码上添加数据的作用,如添加base64的图片。
{ test: /\.(png|jpg|gif)$/, use: [{ // 需要下载file-loader和url-loader loader: "url-loader", options: { limit: 5 * 1024, //小于5kb将会已base64位图片打包处理 // 图片文件输出的文件夹 outputPath: help.assetsPath("images"), name: '[name].[ext]' } }] }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, outputPath: help.assetsPath("fonts") } }, 复制代码
以上所述就是小编给大家介绍的《渐进式配置webpack4单页面和多页面(一)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 渐进式配置webpack4单页面和多页面(二)
- 渐进式动画解决方案
- vuex 渐进式教程(一)
- 渐进式 Unbundled 开发工具探索之路
- React Fiber 渐进式组件遍历详解
- 大数据系统云原生渐进式演进最佳实践
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。