前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

构建方式篇|博客系列

# 一、几种开发工具

每次要编译代码时,手动运行 npm run build 就会变得很麻烦。

不知道你有没有使用过类似于vue-cli这样的脚手架工具, 在使用它们的时候, 每次只要执行npm run start这样的指令就可以创建一个本地的web服务器, 然后打开一个例如localhost:8080这样的端口页面, 同时还有热更新等功能.

其实这些功能的实现都是vue-cli内部使用了webpack.

webpack中有几个不同的选项,可以帮助你在代码发生变化后自动编译代码.

# webpack’s Watch Mode(观察者模式)

观察者模式, 只需要在package.json里配置一个脚本命令:

"scripts": {
	"watch": "webpack --watch"
}
@前端进阶之旅: 代码已经复制到剪贴板

使用npm run watch命令之后, 会看到编译过程, 但是不会退出命令行, 而是实时监控文件.

比如你在重新修改了本地的代码并保存后, 它会重新进行编译, 不需要我们手动再执行编译指令, 缺点是你需要手动刷新页面才能看到更改效果.

(--watch也可以简写为-w)

# webpack-dev-server

使用webpack-dev-server会为你提供一个简单的web服务器, 它的作用就是监听文件的改变并自动编译, 同时会自动刷新页面. 比观察者模式厉害.

使用步骤:

  • 安装: $ npm i --save-dev webpack-dev-server
  • 添加脚本命令: "start": "webpack-dev-server --open"

使用此指令效果:

不会生成dist文件夹, 而是开启了一个本地的web服务器localhost:8080

每次修改了本地代码之后, 都会重新自动编译, 并刷新页面

其它配置项:

webpack-dev-server也有很多配置项能在webpack.config.js中配置

只需要在devServer里进行配置, 例如:

module.exports = {
    devServer: {
        contentBase: './dist', // 告诉服务器从哪里提供内容
        host: '0.0.0.0', // 默认是 localhost
        port: 8000, // 端口号, 默认是8080
        open: true, // 是否自动打开浏览器
        hot: true, // 启用 webpack 的模块热替换特性
        hotOnly: true // 当编译失败之后不进行热更新
    }
}
@前端进阶之旅: 代码已经复制到剪贴板

如果你使用了这个功能之后, 你就会发现, 它就有点vue-cli的样子了.

更多关于devServer的配置可以查看这里: 开发中Server。

# webpack-dev-middleware

# 基本使用

webpack-dev-middleware 是一个容器(wrapper),它可以把 webpack 处理后的文件传递给一个服务器(server)。

webpack-dev-server 能够开启一个本地的web服务器, 就是因为在内部使用了它,但是, 它也可以作为一个包来单独使用.

这里我就以官方的案例来进行讲解.

使用webpack-dev-middleware配合express server来介绍它的功能.

(express是一个很精简的Node.js开发框架,如果你之前没用过也没关系,使用起来很简单。)

先来说下我的需求, 我想要实现一个这个功能:

  • 配置一条script指令让它能运行一个本地web服务器(也就是能够在localhost: 3000中查看页面)
  • 每次修改本地代码能够重新编译
  • 但是不会自动刷新页面
  1. 安装所需的依赖:
$ npm i --save-dev webpack-dev-middleware express
@前端进阶之旅: 代码已经复制到剪贴板
  1. 在项目的根目录下创建一个server.js文件用来编写本地服务:
// server.js
const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')

const app = express()
const config = require('./webpack.config')
const compiler = webpack(config)
// 把 webpack 处理后的文件传递给一个服务器
app.use(webpackDevMiddleware(compiler))

app.listen(3000, function() {
    console.log('Example app listening on port 3000!\n');
})
@前端进阶之旅: 代码已经复制到剪贴板
  1. 在package.json里配置指令运行server.js:
{
    "scripts": {
        "server": "node server.js"
    }
}
@前端进阶之旅: 代码已经复制到剪贴板

# publicPath配置项

在学习这里的时候, 我顺便也了解到了webpack.config.js 中output的另一个属性publicPath.

开始看文档 output.outputPath的时候没太看懂.

后来我结合webpack-dev-middleware来试了一下它.

首先修改一下webpack.config.js的配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    devtool: 'inline-source-map', // 仅开发环境报错追踪
    plugins: [
        new CleanWebpackPlugin({
            cleanAfterEveryBuildPatterns: ['dist']
        }),
        new HtmlWebpackPlugin({
            title: 'Webpack Output2',
            filename: 'index.html',
            template: 'src/index.html'
        })
    ],
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
+       publicPath: '/assets/'
    }
}
@前端进阶之旅: 代码已经复制到剪贴板

然后修改一下server.js:

// server.js
const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')

const app = express()
const config = require('./webpack.config')
const compiler = webpack(config)
// 把webpack 处理后的文件传递给一个服务器
app.use(webpackDevMiddleware(compiler 
+	,{
+	    publicPath: config.output.publicPath
+	}
))

app.listen(3000, function() {
    console.log('Example app listening on port 3000!\n');
})
@前端进阶之旅: 代码已经复制到剪贴板

保存上面👆两个文件, 然后重新执行npm run server, 打开localhost:3000 会发现页面显示的是:

Cannot GET /
@前端进阶之旅: 代码已经复制到剪贴板

你需要打开localhost:3000/assets/才能看到正确的页面.

并且如果项目里有对资源的引用的话, 也会自动加上publicPath的前缀:

icon.png => 变为 /assets/icon.png
@前端进阶之旅: 代码已经复制到剪贴板

此选项指定在浏览器中所引用的「此输出目录对应的公开 URL」。

注⚠️:

如果没有配置output.publicPath和webpack-dev-middleware的publicPath, 则默认都会是"",以根目录作为配置项。

如果配置了output.publicPath, 则webpack-dev-middleware中的publicPath也要和它一样才行。

# 二、不同环境的构建

开发环境和生产环境的构建目标差异是非常大的.

  • 开发环境中, 我们可能有实时重新加载(live reloading) 、热模块替换(hot module replacement)等能力
  • 生产环境中, 我们更加关注更小的bundle(压缩输出), 更轻量的source map, 还有更优化的资源等.

所以为了遵循逻辑分离, 我们可以为每个环境编写彼此独立的webpack配置.

虽说是想要编写各自独立的配置, 但是肯定也有一些公用的配置项, 我们可以将这些公用的配置项提取出来, 然后不同的配置写在不同的文件中.

(第二节教材案例GitHub地址: LinDaidai/webpack-example/webpak-merge ⚠️:请仔细查看README说明)

# webpack-merge

最终, 为了将这些配置项合并在一起, 我们需要用到webpack-merge工具.

首先安装这个工具:

$ npm i --save-dev webpack-merge
@前端进阶之旅: 代码已经复制到剪贴板

然后让我们将原本的webpack.config.js拆开, 编写成三个不同的webpack配置文件:

  webpack-demo
  |- package.json
- |- webpack.config.js
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
  |- /dist
  |- /src
    |- index.js
    |- math.js
  |- /node_modules
@前端进阶之旅: 代码已经复制到剪贴板

webpack.common.js:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
    entry: './src/index.js',
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'webpack bundle'
        })
    ]
}
@前端进阶之旅: 代码已经复制到剪贴板

webpack.dev.js:

← 基础篇自定义plugin篇 →

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合