下载资源文件、相关配置 # 基础配置
将支持以下功能:
- 分离开发环境、生产环境配置
- 模块化开发
- sourceMap 定位警告和错误
- 动态生成引入 bundle.js 的 HTML5 文件
- 实时编译
- 封装编译、打包命令
- 加载图片、字体、CSS、SCSS、PostCSS
- React+TypeScript
1.新建项目
mkdir REACT-CLIcd REACT-CLI// 初始化项目npm init -ymkdir srccd srccode index.js
2.安装 webpack
yarn add webpack webpack-cli -D
目录结构如下:
- node_modules - src - index.js - package.json
3.新建 webpack 配置文件
// 创建 config 目录mkdir config// 进入 config 目录cd ./config// Windows环境vscode创建通用环境配置文件code webpack.common.js// 创建开发环境配置文件code webpack.dev.js// 创建生产环境配置文件code webpack.prod.js
4.使用 webpack-marge 合并通用配置和特定环境配置
yarn add webpack-merge -D
通用环境配置::
// webpack.common.jsmodule.exports = {};
开发环境配置:
// webpack.dev.jsconst { merge } = require("webpack-merge");const common = require("./webpack.common");module.exports = merge(common, {}); // 暂不添加配置
生产环境配置:
// webpack.prod.jsconst { merge } = require("webpack-merge");const common = require("./webpack.common");module.exports = merge(common, {}); // 暂不添加配置
项目结构如下:
- config - webpack.common.js - webpack.dev.js - webpack.prod.js- node_modules- src - index.js- package.json
入口 entry
修改 webpack.commom.js:
module.exports = { // 入口 entry: { index: './src/index.js', },}
输出(output)
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。 生产环境的 output 需要通过 contenthash 值来区分版本和变动,可达到清缓存的效果,而本地环境为了构建效率,则不引入contenthash。
config目录下新增 paths.js,封装路径方法:
const fs = require('fs')const path = require('path')const appDirectory = fs.realpathSync(process.cwd());const resolveApp = relativePath => path.resolve(appDirectory, relativePath);module.exports = { resolveApp, appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), appSrc: resolveApp('src'), appDist: resolveApp('dist'), appTsConfig: resolveApp('tsconfig.json')}
修改开发环境配置文件 webpack.dev.js:
const paths = require('./paths')module.exports = merge(common, { // 输出 output: { // bundle 文件名称 filename: '[name].bundle.js', // bundle 文件路径 path: paths.appDist, // 编译前清除目录 clean: true },})
修改生产环境配置文件 webpack.prod.js:
const paths = require('./paths')module.exports = merge(common, { // 输出 output: { // bundle 文件名称 【只有这里和开发环境不一样】 filename: '[name].[contenthash].bundle.js', // bundle 文件路径 path: paths.appDist, // 编译前清除目录 clean: true },})
[name]
chunk name(例如[name].js
->app.js
)。如果 chunk 没有名称,则会使用其 id 作为名称
[contenthash]
- 输出文件内容的 md4-hash(例如[contenthash].js
->4ea6ff1de66c537eb9b2.js
)
模式mode
通过 mode 配置选项,告知 webpack 使用相应模式的内置优化。 - development:
会将
DefinePlugin
中 process.env.NODE_ENV
的值设置为 development
。为模块和 chunk 启用有效的名称。- production:
会将
DefinePlugin
中 process.env.NODE_ENV
的值设置为 production
。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin
,FlagIncludedChunksPlugin
,ModuleConcatenationPlugin
,NoEmitOnErrorsPlugin
和 TerserPlugin
。修改开发环境配置文件 webpack.dev.js:
module.exports = merge(common, { // 开发模式 mode: 'development', ...})
修改生产环境配置文件 webpack.prod.js:
module.exports = merge(common, { // 生产模式 mode: 'production', ...})
Source Map
开发时,webpack 将我们写的代码经过编译后,很难追踪到 error 和 warning 在源代码中的原始位置。source map可以将编译后的代码映射回原始源代码。
修改开发环境配置文件 webpack.dev.js:
module.exports = merge(common, { // 开发工具,开启 source map,编译调试 devtool: 'eval-cheap-module-source-map',})
source map 有许多 可用选项。本例选择的是
eval-cheap-module-source-map
完成上述配置后,可以通过
npx webpack --config config/webpack.prod.js
打包编译编译后,会生成这样的目录结构:
打包编译结果
webpack-dev-server
在每次编译代码时,手动运行
npx webpack --config config/webpack.prod.js
会显得很麻烦,webpack-dev-server 可以帮助我们在代码发生变化后自动编译代码。 安装:yarn add webpack-dev-server -D
修改开发环境配置文件 webpack.dev.js:
module.exports = merge(common, { devServer: { // 告诉服务器从哪里提供内容,只有在你想要提供静态文件时才需要。 static: './dist', },})
完成上述配置后,可以通过
npx webpack serve --open --config config/webpack.dev.js
实时编译。HtmlWebpackPlugin
引入
HtmlWebpackPlugin
插件,生成一个 HTML5 文件,其中会引用打包生成的 bundle 文件。 安装:yarn add html-webpack-plugin -D
修改通用环境配置文件 webpack.commom.js:
module.exports = { ... plugins: [ // 生成html,自动引入所有bundle new HtmlWebpackPlugin({ title: 'release_v0', }), ],}
重新 webpack 编译
npx webpack --config config/webpack.prod.js
,生成的目录结构如下打包入html
新生成了 index.html,修改了title,动态引入了 bundle.js 文件:
<!doctype html><html> <head> <meta charset="utf-8"> <title>release_v0</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <script defer="defer" src="index.7d02a7c9bcd86981b6f4.bundle.js"></script> </head> <body> </body> </html>
优化执行命令
上述配置文件完成后,优化 webpack 的实时编译、打包编译指令。
通过
cross-env
配置环境变量,区分开发环境和生产环境。安装:
yarn add cross-env -D
修改 package.json:
"scripts": { "dev": "cross-env NODE_ENV=development webpack serve --open --config config/webpack.dev.js", "build": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js" }
现在可以运行 webpack 指令:
npm run dev
:本地构建
npm run build
:生产打包
接下来继续完善配置,用 Webpack 搭建一个 SASS + TS + React 的项目,并且支持: - 加载图片 - 加载字体 - 加载 CSS - 使用 SASS - 使用 PostCSS,并自动为 CSS 规则添加前缀,解析最新的 CSS 语法,引入 css-modules 解决全局命名冲突问题 - 使用 React - 使用 TypeScript
加载图片、字体
在 webpack 5 中,有内置的
Asset Modules
,不必再引入file-loader
和 url-loader
处理文件了。在实际开发过程中,推荐将大图片、字体文件压缩上传至 CDN,提高加载速度。
修改通用环境配置文件 webpack.commom.js:
const paths = require('./paths');module.exports = { ... module: { rules: [ { test: /\.(png|svg|jpg|jpeg|gif)$/i, include: paths.appSrc, type: 'asset/resource', }, { test: /.(woff|woff2|eot|ttf|otf)$/i, include: [ paths.appSrc, ], type: 'asset/resource', }, ], }, ...}
加载CSS相关
- style-loader
style-loader
就是把 CSS
插入到 DOM
中,通过使用多个 <style></style>
自动把 styles
插入到 DOM
中.- css-loader
css-loader
对 @import
和 url()
进行处理,就像 js 解析import/require()
一样,让 CSS 也能模块化开发。- sass-loader
sass-loader
会加载sass/scss文件
并且将他们编译成CSS
- postcss-loader 1.可以自动为 CSS 规则添加前缀 2.将最新的 CSS 语法转换成大多数浏览器都能理解的语法 3.css-modules 解决全局命名冲突问题
安装相关库和依赖:
yarn add style-loader css-loader -Dyarn add sass-loader sass -Dyarn add postcss-loader postcss postcss-preset-env -D
修改通用环境配置文件 webpack.commom.js:
module.exports = { ... module: { ... rules: [ { test: /\.css$/, include: paths.appSrc, use: [ // 将 JS 字符串生成为 style 节点 "style-loader", // 将 CSS 转化成 CommonJS 模块 "css-loader", ], }, { test: /\.module\.(scss|sass)$/, include: paths.appSrc, use: [ // 将 JS 字符串生成为 style 节点 "style-loader", // 将 CSS 转化成 CommonJS 模块 { loader: "css-loader", options: { // Enable CSS Modules features modules: true, importLoaders: 2, // 0 => no loaders (default); // 1 => postcss-loader; // 2 => postcss-loader, sass-loader }, }, // 将 PostCSS 编译成 CSS { loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ // postcss-preset-env 包含 autoprefixer "postcss-preset-env", ], ], }, }, }, // 将 Sass 编译成 CSS "sass-loader", ], }, ] } ... }
JS相关
yarn add babel-loader @babel/core @babel/preset-env -D
babel-loader
使用 Babel 加载 ES2015+ 代码并将其转换为 ES5
@babel/core
Babel 编译的核心包
@babel/preset-env
Babel 编译的预设,可以理解为 Babel 插件的超集
使用 React + TypeScript
yarn add react react-dom @types/react @types/react-dom -Dyarn add typescript esbuild-loader -D//为提高性能,摒弃了传统的 ts-loader,选择最新的 esbuild-loader。
修改通用环境配置文件 webpack.commom.js:
module.exports = { resolve: { extensions: ['.tsx', '.ts', '.js'], }, module: { rules: [ { test: /\.(js|ts|jsx|tsx)$/, include: paths.appSrc, use: [ { loader: 'esbuild-loader', options: { loader: 'tsx', target: 'es2015', }, } ] }, ] } }
为兼容 TypeScript 文件,新增 typescript 配置文件
tsconfig.json
:tsconfig相关提示{ "compilerOptions": { "outDir": "./dist/", "noImplicitAny": true, "module": "es6", "target": "es5", "strict": true,//通过启用TypeScript的strict编译器选项,编译器将在最严格的模式下运行,在运行之前捕获更多类型问题。 "jsx": "react", "allowJs": true, "moduleResolution": "node", "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true,//强制统一不同操作系统的文件名 "importHelpers": true,//通过启用TypeScript的importlpers编译器选项,编译器将使用tslib包,并减少输出的大小 }}