项目代码:Github

    1. 新建项目src/index.ts

      1. git init
      2. pnpm init
      3. pnpm install
      4. npx tsc --init

      image.png

    2. 在 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

    1. {
    2. "name": "webpack-demo",
    3. "version": "1.0.0",
    4. "description": "",
    5. "main": "index.js",
    6. "scripts": {
    7. "build": "rm -rf dist && webpack --config ./config/webpack.prod.js",
    8. "serve": "webpack serve --config ./config/webpack.dev.js",
    9. "deploy": "http-server dist -p 8080"
    10. },
    11. "keywords": [],
    12. "author": "",
    13. "license": "ISC",
    14. "devDependencies": {
    15. "@babel/core": "^7.17.10",
    16. "@babel/preset-env": "^7.17.10",
    17. "@babel/preset-typescript": "^7.16.7",
    18. "@vue/compiler-sfc": "^3.2.33",
    19. "babel-loader": "^8.2.5",
    20. "css-loader": "^6.7.1",
    21. "html-webpack-plugin": "^5.5.0",
    22. "mini-css-extract-plugin": "^2.6.0",
    23. "sass": "^1.51.0",
    24. "sass-loader": "^12.6.0",
    25. "style-loader": "^3.3.1",
    26. "typescript": "^4.6.4",
    27. "vue-loader": "^17.0.0",
    28. "webpack": "^5.72.0",
    29. "webpack-cli": "^4.9.2",
    30. "webpack-dev-server": "^4.9.0",
    31. "webpack-merge": "^5.8.0"
    32. },
    33. "dependencies": {
    34. "http-server": "^14.1.0",
    35. "vue": "^3.2.33"
    36. }
    37. }
    1. 识别声明 vue 文件,babel插件配置。.vue 文件的解析还需要 @vue/compoiler-sfc 这个包。

      1. declare module "*.vue" {
      2. import type { DefineComponent } from "vue";
      3. const component: DefineComponent<{}, {}, any>;
      4. export default component;
      5. }
      1. module.exports = {
      2. presets: [
      3. "@babel/preset-env",
      4. [
      5. "@babel/preset-typescript",
      6. {
      7. allExtensions: true, //支持所有文件扩展名
      8. },
      9. ],
      10. ],
      11. };

      ```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 for createElement. This only applies when targeting react 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, / Disallow imports, requires 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 from node_modules. Only applicable with allowJs. /

      / 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 erasing const 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 account null and undefined. / // “strictFunctionTypes”: true, / When assigning functions, check to ensure parameters and the return values are subtype-compatible. / // “strictBindCallApply”: true, / Check that the arguments for bind, call, and apply 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 when this is given the type any. / // “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. / } }

    1. 4. 配置文件拆分
    2. webpack.config.js 可以按照工程化思维拆分成 webpack.base.jswebpack.dev.jswebpack.prod.js 三个文件,基本配置放在 base 文件,用 webpack-merge 合并到 dev/prod 文件。
    3. ```javascript
    4. const HtmlWebpackPlugin = require('html-webpack-plugin')
    5. const { VueLoaderPlugin } = require("vue-loader");
    6. const { DefinePlugin } = require('webpack');
    7. const path = require("path");
    8. const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    9. const devMode = process.env.NODE_ENV !== "production";
    10. module.exports = {
    11. // 入口文件
    12. entry: './src/index.ts',
    13. // 打包输出
    14. output: {
    15. filename: 'main.[contenthash].js',
    16. path: path.resolve(__dirname, '../dist'),
    17. /*
    18. * chunkFilename用来打包require.ensure方法中引入的模块,如果该方法中没有引入任何模块则不会生成任何chunk块文件
    19. * 比如在main.js文件中,require.ensure([],function(require){alert(11);}),这样不会打包块文件
    20. * 只有这样才会打包生成块文件require.ensure([],function(require){alert(11);require('./greeter')})
    21. * 或者这样require.ensure(['./greeter'],function(require){alert(11);})
    22. * chunk的hash值只有在require.ensure中引入的模块发生变化,hash值才会改变
    23. * 注意:对于不是在ensure方法中引入的模块,此属性不会生效,只能用CommonsChunkPlugin插件来提取
    24. *
    25. */
    26. chunkFilename:'[chunkhash:8].chunk.js'
    27. },
    28. plugins: [
    29. // 配置html模板插件
    30. new HtmlWebpackPlugin({
    31. title: 'Webpack demo',
    32. template: './src/assets/index.html',
    33. }),
    34. new VueLoaderPlugin(),
    35. new DefinePlugin({
    36. BASE_URL: "'./'",
    37. __VUE_OPTIONS_API__: true, // 这里必须是布尔值,不能写成字符串
    38. __VUE_PROD_DEVTOOLS__: false // 这里必须是布尔值,不能写成字符串
    39. }),
    40. ],
    41. resolve:{
    42. // 设置路径别名
    43. alias: {
    44. '@': path.resolve(__dirname, '../src'),
    45. },
    46. // 省略拓展名,虽然会带来一些便利,但实际上会在一定程度上影响 webpack 的运行效率,不推荐修改
    47. extensions: ['.ts', '.js', '.json']
    48. },
    49. module: {
    50. rules: [
    51. // 将 ts/js 用 babel 编译成 es5
    52. {
    53. test: /\.(t|j)s$/,
    54. exclude: /node_modules/,
    55. use: {
    56. loader: "babel-loader",
    57. options: {
    58. cacheDirectory: true,
    59. },
    60. },
    61. },
    62. {
    63. test: /\.vue$/,
    64. use: "vue-loader",
    65. },
    66. // dev环境用style-loader,prod环境用miniCss
    67. {
    68. test: /\.(sa|sc|c)ss$/,
    69. use: [devMode ? "style-loader" : MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
    70. },
    71. // 图片类型打包
    72. {
    73. test: /\.(png|svg|jpe?g|gif)$/,
    74. type: "asset",
    75. generator: {
    76. filename: "images/[name]-[hash][ext]",
    77. },
    78. },
    79. // 字体类型打包
    80. {
    81. test: /\.(eot|svg|ttf|woff2?|)$/,
    82. type: "asset/resource",
    83. generator: {
    84. filename: "fonts/[name]-[hash][ext]",
    85. },
    86. },
    87. ],
    88. },
    89. };
    1. const { merge } = require("webpack-merge");
    2. const baseConfig = require("./webpack.base.js");
    3. module.exports = merge(baseConfig, {
    4. mode: 'development',
    5. // webpack升级到5.0后,target默认值值会根据package.json中的browserslist改变,导致devServer的自动更新失效
    6. // 所以 development 环境下直接配置成 web
    7. target: "web",
    8. devServer: {
    9. hot: true, // 启用热模块替换
    10. open: true, // 打开默认浏览器
    11. proxy: {
    12. "/api": {
    13. // 需要代理到的真实目标服务器,如/api/user会被代理到https://www.juejin.cn/api/user
    14. target: "https://www.juejin.cn",
    15. // 是否更改代理后请求的headers中host地址,某些安全级别较高的服务器会对此做校验
    16. changeOrigin: true,
    17. // 默认情况下不接受将请求转发到https的api服务器上,如果希望支持,可以设置为false
    18. secure: false,
    19. // 默认情况下/api也会写入到请求url中,通过这个配置可以将其删除
    20. pathRewrite: {
    21. "^/api": "/",
    22. },
    23. },
    24. }
    25. },
    26. })
    1. const { merge } = require("webpack-merge");
    2. const baseConfig = require("./webpack.base.js");
    3. const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    4. module.exports = merge(baseConfig, {
    5. mode: "production",
    6. // 代码分隔
    7. optimization: {
    8. splitChunks: {
    9. // 选择对哪些文件进行拆分,默认是async,即只对动态导入的文件进行拆分
    10. chunks: "all",
    11. // 提取chunk的最小体积
    12. minSize: 20000,
    13. // 要提取的chunk最少被引用次数
    14. minChunks: 1,
    15. // 对要提取的trunk进行分组,根据业务逻辑去拆包
    16. cacheGroups: {
    17. // 匹配node_modules中的三方库,将其打包成一个trunk
    18. defaultVendors: {
    19. test: /[\\/]node_modules[\\/]/,
    20. name: "vendors",
    21. priority: -10,
    22. },
    23. default: {
    24. // 将至少被两个trunk引入的模块提取出来打包成单独trunk
    25. minChunks: 2,
    26. name: "default",
    27. priority: -20,
    28. },
    29. },
    30. },
    31. },
    32. // 抽离出css成一个单独文件,生产环境用,这样在浏览器中可以拥有更好的加载效率
    33. plugins: [new MiniCssExtractPlugin()],
    34. });
    1. index.html/main.ts/App.vue文件
      1. <!DOCTYPE html>
      2. <html lang="zh">
      3. <head>
      4. <meta charset="UTF-8">
      5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
      6. <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
      7. <title><%= htmlWebpackPlugin.options.title %></title>
      8. </head>
      9. <body>
      10. <div id="app"></div>
      11. </body>
      12. </html>
      ```typescript import { createApp } from “vue”; import App from “@/App.vue”; import ‘@/style.css’

    createApp(App).mount(“#app”);

    1. ```vue
    2. <template>
    3. <div class="app">
    4. <h1 class="example">{{ name }}</h1>
    5. <img src="../static/nature.jpg" alt="backImg">
    6. </div>
    7. </template>
    8. <script lang="ts">
    9. import { defineComponent } from "vue";
    10. export default defineComponent({
    11. setup() {
    12. const name = "Hello Webpack5 Vue3";
    13. return {
    14. name,
    15. };
    16. },
    17. });
    18. </script>
    19. <style scoped lang="scss">
    20. .app{
    21. .example{
    22. color: blue;
    23. }
    24. img{
    25. height: 200px;
    26. width: 200px;
    27. }
    28. }
    29. </style>