项目代码:Github
新建项目src/index.ts
git init
pnpm init
pnpm install
npx tsc --init
在 package.json 文件中添加打包脚本:
ts/js打包编译:babel-loader,@babel/core,@babel/preset-env,@babel/preset-typescript
vue打包编译:vue,vue-loader,@vue/compiler-sfc
webpack打包编译:webpack,webpack-cli
自动热更新server:webpack-dev-server
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "rm -rf dist && webpack --config ./config/webpack.prod.js",
"serve": "webpack serve --config ./config/webpack.dev.js",
"deploy": "http-server dist -p 8080"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.17.10",
"@babel/preset-env": "^7.17.10",
"@babel/preset-typescript": "^7.16.7",
"@vue/compiler-sfc": "^3.2.33",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.6.0",
"sass": "^1.51.0",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"typescript": "^4.6.4",
"vue-loader": "^17.0.0",
"webpack": "^5.72.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.0",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"http-server": "^14.1.0",
"vue": "^3.2.33"
}
}
识别声明 vue 文件,babel插件配置。.vue 文件的解析还需要 @vue/compoiler-sfc 这个包。
declare module "*.vue" {
import type { DefineComponent } from "vue";
const component: DefineComponent<{}, {}, any>;
export default component;
}
module.exports = {
presets: [
"@babel/preset-env",
[
"@babel/preset-typescript",
{
allExtensions: true, //支持所有文件扩展名
},
],
],
};
```json { “compilerOptions”: { / Visit https://aka.ms/tsconfig.json to read more about this file /
/ Projects / // “incremental”: true, / Enable incremental compilation / // “composite”: true, / Enable constraints that allow a TypeScript project to be used with project references. / // “tsBuildInfoFile”: “./“, / Specify the folder for .tsbuildinfo incremental compilation files. / // “disableSourceOfProjectReferenceRedirect”: true, / Disable preferring source files instead of declaration files when referencing composite projects / // “disableSolutionSearching”: true, / Opt a project out of multi-project reference checking when editing. / // “disableReferencedProjectLoad”: true, / Reduce the number of projects loaded automatically by TypeScript. /
/ Language and Environment / “target”: “es2016”, / Set the JavaScript language version for emitted JavaScript and include compatible library declarations. / “lib”: [“ESNext”,”DOM”], / Specify a set of bundled library declaration files that describe the target runtime environment. / “jsx”: “preserve”, / Specify what JSX code is generated. / // “experimentalDecorators”: true, / Enable experimental support for TC39 stage 2 draft decorators. / // “emitDecoratorMetadata”: true, / Emit design-type metadata for decorated declarations in source files. / // “jsxFactory”: “”, / Specify the JSX factory function used when targeting React JSX emit, e.g. ‘React.createElement’ or ‘h’ / // “jsxFragmentFactory”: “”, / Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. ‘React.Fragment’ or ‘Fragment’. / // “jsxImportSource”: “”, / Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx
.
/ // “reactNamespace”: “”, / Specify the object invoked forcreateElement
. This only applies when targetingreact
JSX emit. / // “noLib”: true, / Disable including any library files, including the default lib.d.ts. / // “useDefineForClassFields”: true, / Emit ECMAScript-standard-compliant class fields. *// Modules / “module”: “ESNext”, / Specify what module code is generated. / // “rootDir”: “./“, / Specify the root folder within your source files. / “moduleResolution”: “node”, / Specify how TypeScript looks up a file from a given module specifier. / “baseUrl”: “.”, / Specify the base directory to resolve non-relative module names. / “paths”: { “@/“: [“src/“], }, / Specify a set of entries that re-map imports to additional lookup locations. / // “rootDirs”: [], / Allow multiple folders to be treated as one when resolving modules. / // “typeRoots”: [], / Specify multiple folders that act like
./node_modules/@types
. / // “types”: [], / Specify type package names to be included without being referenced in a source file. / // “allowUmdGlobalAccess”: true, / Allow accessing UMD globals from modules. / // “resolveJsonModule”: true, / Enable importing .json files / // “noResolve”: true, / Disallowimport
s,require
s or<reference>
s from expanding the number of files TypeScript should add to a project. // JavaScript Support / // “allowJs”: true, / Allow JavaScript files to be a part of your program. Use the
checkJS
option to get errors from these files. / // “checkJs”: true, / Enable error reporting in type-checked JavaScript files. / // “maxNodeModuleJsDepth”: 1, / Specify the maximum folder depth used for checking JavaScript files fromnode_modules
. Only applicable withallowJs
. // Emit / // “declaration”: true, / Generate .d.ts files from TypeScript and JavaScript files in your project. / // “declarationMap”: true, / Create sourcemaps for d.ts files. / // “emitDeclarationOnly”: true, / Only output d.ts files and not JavaScript files. / // “sourceMap”: true, / Create source map files for emitted JavaScript files. / // “outFile”: “./“, / Specify a file that bundles all outputs into one JavaScript file. If
declaration
is true, also designates a file that bundles all .d.ts output. / // “outDir”: “./“, / Specify an output folder for all emitted files. / // “removeComments”: true, / Disable emitting comments. / // “noEmit”: true, / Disable emitting files from a compilation. / // “importHelpers”: true, / Allow importing helper functions from tslib once per project, instead of including them per-file. / // “importsNotUsedAsValues”: “remove”, / Specify emit/checking behavior for imports that are only used for types / // “downlevelIteration”: true, / Emit more compliant, but verbose and less performant JavaScript for iteration. / // “sourceRoot”: “”, / Specify the root path for debuggers to find the reference source code. / // “mapRoot”: “”, / Specify the location where debugger should locate map files instead of generated locations. / // “inlineSourceMap”: true, / Include sourcemap files inside the emitted JavaScript. / // “inlineSources”: true, / Include source code in the sourcemaps inside the emitted JavaScript. / // “emitBOM”: true, / Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. / // “newLine”: “crlf”, / Set the newline character for emitting files. / // “stripInternal”: true, / Disable emitting declarations that have@internal
in their JSDoc comments. / // “noEmitHelpers”: true, / Disable generating custom helper functions like__extends
in compiled output. / // “noEmitOnError”: true, / Disable emitting files if any type checking errors are reported. / // “preserveConstEnums”: true, / Disable erasingconst enum
declarations in generated code. / // “declarationDir”: “./“, / Specify the output directory for generated declaration files. / // “preserveValueImports”: true, / Preserve unused imported values in the JavaScript output that would otherwise be removed. // Interop Constraints / // “isolatedModules”: true, / Ensure that each file can be safely transpiled without relying on other imports. / // “allowSyntheticDefaultImports”: true, / Allow ‘import x from y’ when a module doesn’t have a default export. / “esModuleInterop”: true, / Emit additional JavaScript to ease support for importing CommonJS modules. This enables
allowSyntheticDefaultImports
for type compatibility. / // “preserveSymlinks”: true, / Disable resolving symlinks to their realpath. This correlates to the same flag in node. / “forceConsistentCasingInFileNames”: true, / Ensure that casing is correct in imports. // Type Checking / “strict”: false, / Enable all strict type-checking options. / // “noImplicitAny”: true, / Enable error reporting for expressions and declarations with an implied
any
type.. / // “strictNullChecks”: true, / When type checking, take into accountnull
andundefined
. / // “strictFunctionTypes”: true, / When assigning functions, check to ensure parameters and the return values are subtype-compatible. / // “strictBindCallApply”: true, / Check that the arguments forbind
,call
, andapply
methods match the original function. / // “strictPropertyInitialization”: true, / Check for class properties that are declared but not set in the constructor. / // “noImplicitThis”: true, / Enable error reporting whenthis
is given the typeany
. / // “useUnknownInCatchVariables”: true, / Type catch clause variables as ‘unknown’ instead of ‘any’. / // “alwaysStrict”: true, / Ensure ‘use strict’ is always emitted. / // “noUnusedLocals”: true, / Enable error reporting when a local variables aren’t read. / // “noUnusedParameters”: true, / Raise an error when a function parameter isn’t read / // “exactOptionalPropertyTypes”: true, / Interpret optional property types as written, rather than adding ‘undefined’. / // “noImplicitReturns”: true, / Enable error reporting for codepaths that do not explicitly return in a function. / // “noFallthroughCasesInSwitch”: true, / Enable error reporting for fallthrough cases in switch statements. / // “noUncheckedIndexedAccess”: true, / Include ‘undefined’ in index signature results / // “noImplicitOverride”: true, / Ensure overriding members in derived classes are marked with an override modifier. / // “noPropertyAccessFromIndexSignature”: true, / Enforces using indexed accessors for keys declared using an indexed type / // “allowUnusedLabels”: true, / Disable error reporting for unused labels. / // “allowUnreachableCode”: true, / Disable error reporting for unreachable code. // Completeness / // “skipDefaultLibCheck”: true, / Skip type checking .d.ts files that are included with TypeScript. / “skipLibCheck”: true / Skip type checking all .d.ts files. / } }
4. 配置文件拆分
webpack.config.js 可以按照工程化思维拆分成 webpack.base.js、webpack.dev.js、webpack.prod.js 三个文件,基本配置放在 base 文件,用 webpack-merge 合并到 dev/prod 文件。
```javascript
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require("vue-loader");
const { DefinePlugin } = require('webpack');
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devMode = process.env.NODE_ENV !== "production";
module.exports = {
// 入口文件
entry: './src/index.ts',
// 打包输出
output: {
filename: 'main.[contenthash].js',
path: path.resolve(__dirname, '../dist'),
/*
* chunkFilename用来打包require.ensure方法中引入的模块,如果该方法中没有引入任何模块则不会生成任何chunk块文件
* 比如在main.js文件中,require.ensure([],function(require){alert(11);}),这样不会打包块文件
* 只有这样才会打包生成块文件require.ensure([],function(require){alert(11);require('./greeter')})
* 或者这样require.ensure(['./greeter'],function(require){alert(11);})
* chunk的hash值只有在require.ensure中引入的模块发生变化,hash值才会改变
* 注意:对于不是在ensure方法中引入的模块,此属性不会生效,只能用CommonsChunkPlugin插件来提取
*
*/
chunkFilename:'[chunkhash:8].chunk.js'
},
plugins: [
// 配置html模板插件
new HtmlWebpackPlugin({
title: 'Webpack demo',
template: './src/assets/index.html',
}),
new VueLoaderPlugin(),
new DefinePlugin({
BASE_URL: "'./'",
__VUE_OPTIONS_API__: true, // 这里必须是布尔值,不能写成字符串
__VUE_PROD_DEVTOOLS__: false // 这里必须是布尔值,不能写成字符串
}),
],
resolve:{
// 设置路径别名
alias: {
'@': path.resolve(__dirname, '../src'),
},
// 省略拓展名,虽然会带来一些便利,但实际上会在一定程度上影响 webpack 的运行效率,不推荐修改
extensions: ['.ts', '.js', '.json']
},
module: {
rules: [
// 将 ts/js 用 babel 编译成 es5
{
test: /\.(t|j)s$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
},
},
},
{
test: /\.vue$/,
use: "vue-loader",
},
// dev环境用style-loader,prod环境用miniCss
{
test: /\.(sa|sc|c)ss$/,
use: [devMode ? "style-loader" : MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
// 图片类型打包
{
test: /\.(png|svg|jpe?g|gif)$/,
type: "asset",
generator: {
filename: "images/[name]-[hash][ext]",
},
},
// 字体类型打包
{
test: /\.(eot|svg|ttf|woff2?|)$/,
type: "asset/resource",
generator: {
filename: "fonts/[name]-[hash][ext]",
},
},
],
},
};
const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.base.js");
module.exports = merge(baseConfig, {
mode: 'development',
// webpack升级到5.0后,target默认值值会根据package.json中的browserslist改变,导致devServer的自动更新失效
// 所以 development 环境下直接配置成 web
target: "web",
devServer: {
hot: true, // 启用热模块替换
open: true, // 打开默认浏览器
proxy: {
"/api": {
// 需要代理到的真实目标服务器,如/api/user会被代理到https://www.juejin.cn/api/user
target: "https://www.juejin.cn",
// 是否更改代理后请求的headers中host地址,某些安全级别较高的服务器会对此做校验
changeOrigin: true,
// 默认情况下不接受将请求转发到https的api服务器上,如果希望支持,可以设置为false
secure: false,
// 默认情况下/api也会写入到请求url中,通过这个配置可以将其删除
pathRewrite: {
"^/api": "/",
},
},
}
},
})
const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.base.js");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = merge(baseConfig, {
mode: "production",
// 代码分隔
optimization: {
splitChunks: {
// 选择对哪些文件进行拆分,默认是async,即只对动态导入的文件进行拆分
chunks: "all",
// 提取chunk的最小体积
minSize: 20000,
// 要提取的chunk最少被引用次数
minChunks: 1,
// 对要提取的trunk进行分组,根据业务逻辑去拆包
cacheGroups: {
// 匹配node_modules中的三方库,将其打包成一个trunk
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
priority: -10,
},
default: {
// 将至少被两个trunk引入的模块提取出来打包成单独trunk
minChunks: 2,
name: "default",
priority: -20,
},
},
},
},
// 抽离出css成一个单独文件,生产环境用,这样在浏览器中可以拥有更好的加载效率
plugins: [new MiniCssExtractPlugin()],
});
- index.html/main.ts/App.vue文件
```typescript import { createApp } from “vue”; import App from “@/App.vue”; import ‘@/style.css’<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
</body>
</html>
createApp(App).mount(“#app”);
```vue
<template>
<div class="app">
<h1 class="example">{{ name }}</h1>
<img src="../static/nature.jpg" alt="backImg">
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {
const name = "Hello Webpack5 Vue3";
return {
name,
};
},
});
</script>
<style scoped lang="scss">
.app{
.example{
color: blue;
}
img{
height: 200px;
width: 200px;
}
}
</style>