webpack基礎(chǔ)使用(四)

十四、ts
  1. ts-loader幫助我們處理ts文件, 編譯的時(shí)候就可以處理語(yǔ)法錯(cuò)誤。
// 安裝
yarn add ts-loader --dev

// webpack.config.js
entry: './src/index.js' => entry: './src/index.ts'

// webpack.config.js
      {
        test: /\.ts$/,
        use: ['ts-loader']
      }
  1. preset-typescript,支持polyfill填充,進(jìn)行語(yǔ)法轉(zhuǎn)化。但是不能再編譯時(shí)候就判斷語(yǔ)法錯(cuò)誤。
// 安裝
yarn add @babel/preset-typescript --dev

// webpack.config.js
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        // use: ['ts-loader']
        use: ['babel-loader']
      }

// babel.config.js
module.exports = {
    presets: [
      [
        '@babel/preset-env',
        {
          useBuiltIns: 'usage',
          // 默認(rèn)版本2
          corejs: 3
        }
      ],
      // 識(shí)別ts文件
      [ '@babel/preset-typescript' ]
    ]
  }
  1. 結(jié)合使用
// package.json
"scripts": {
    // --noEmit 不生成文件,只是校驗(yàn)
    "build": "tsc --noEmit &&  webpack",
    "serve": "webpack serve"
  }
十四、環(huán)境
  1. paths.js, 不能叫path, 會(huì)內(nèi)部重名.
// 整體處理webpack config里面的路徑
// 這里就不使用相對(duì)路徑
const path = require('path')

const appDir = process.cwd()

const resolveApp = (relativePath) => {
  return path.resolve(appDir, relativePath)
}

module.exports = resolveApp
  1. 公共配置部分webpack.common.js

const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { DefinePlugin } = require('webpack')
const { merge } = require('webpack-merge')

// 導(dǎo)入其它的配置
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

// 定義對(duì)象保存 base 配置信息
const commonConfig = {
    // 反而沒有報(bào)錯(cuò)( 相對(duì)路徑, 相對(duì)于content配置路徑) 
    // 這里content沒有配置,就找的是package.json里面的webpack config的目錄相對(duì)路徑
    entry: './src/index.js',
    devtool: 'source-map',
    resolve: {
      // 添加新的擴(kuò)展名
      extensions: [".js", ".json", '.ts', '.jsx', '.vue'], 
      // 添加別名
      // import Home from './components/Home' 
      // =>
      // import Home from '@/components/Home'
      alias: {
        // 使用相對(duì)路徑
        '@': resolveApp('./src')
        //'@': path.resolve(__dirname, './src')
      }
    },
    output: { 
      filename: 'js/main.js',
      // 輸出到哪兒
      // 使用相對(duì)路徑
      path: resolveApp('./dist'),
      // path: path.join(__dirname, 'dist'),
      // 默認(rèn)空字符串, 瀏覽量會(huì)幫我們添加/
      // publicPath: ''
      // 自己添加/, 但是這樣本地路徑會(huì)找不到
      // publicPath: '/'
      // 相對(duì)路徑, 本地可以訪問,但是webpack serve會(huì)找不到 
      // publicPath: './'
      // publicPath: '/lg'
      // assetModuleFilename: 'img/[name].[hash:4][ext]'
    }, 
    module: {
      rules: [
        {
          test: /\.css$/,
          use: ['style-loader', {
            loader: 'css-loader',
            options: {
              // 代表向前找一個(gè)loader處理
              importLoaders: 1,
              esModule: false
            }
          }, 'postcss-loader']
        },
        {
          test: /\.less$/,
          use: ['style-loader', {
            loader: 'css-loader',
            options: {
              // 代表向前找一個(gè)loader處理
              importLoaders: 1,
              esModule: false
            }
          }, 'postcss-loader', 'less-loader']
        },
        // 全部轉(zhuǎn)成base64
        // {
        //   test:/\.(png|svg|gif|jpe?g)$/,
        //   type: 'asset/inline'
        // }
        // 使用
        {
          test:/\.(png|svg|gif|jpe?g)$/,
          type: 'asset',
          generator: {
            filename: 'img/[name].[hash:4][ext]'
          },
          parser: {
            dataUrlCondition: {
              maxSize: 20 * 1024
            }
          }
        },
        {
          test: /\.(ttf|woff2?)$/,
          type: 'asset/resource',
          generator: {
            filename: 'font/[name].[hash:3][ext]'
          }
        },
        {
          // js或者jsx
          test: /\.jsx?$/,
          // 防止node_modules中的庫(kù)也使用了babel,導(dǎo)致干擾
          exclude: /node_modules/,
          use: [ 'babel-loader' ]
        },
        {
          test: /\.vue$/,
          exclude: /node_modules/,
          use: ['vue-loader']
        },
        {
          test: /\.ts$/,
          exclude: /node_modules/,
          // use: ['ts-loader']
          use: ['babel-loader']
        }
      ]
    },
    plugins: [
      new HtmlWebpackPlugin({
        title: 'jerry-webpack-plugin',
        template: './public/index.html'
      }),
      // 定義常量
      new DefinePlugin({
        // 這里要添加雙引號(hào),DefinePlugin會(huì)把數(shù)據(jù)原封不動(dòng)返回
        BASE_URL: '"./"'
      }),
      // 針對(duì)vue-loader > 15的版本,需要手動(dòng)設(shè)置插件
      new VueLoaderPlugin()
    ]
  }

module.exports = (env) => {
    const isProduction = env.production

    // 設(shè)置線程環(huán)境, 讓config中也可以判斷環(huán)境
    process.env.NODE_ENV = isProduction ? 'production' : 'development'
  
    // 依據(jù)當(dāng)前的打包模式來(lái)合并配置
    const config = isProduction ? prodConfig : devConfig
  
    const mergeConfig = merge(commonConfig, config)
  
    return mergeConfig
  }
  1. 正式環(huán)境webpack.prod.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
  mode: 'production', 
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          // 省略了to,to默認(rèn)output.path的文件夾
          from: 'public',
          globOptions: {
            // index.html上面已經(jīng)操作過(guò)了,需要排除。
            // 默認(rèn)從項(xiàng)目根找, **代表從當(dāng)前目錄找
            ignore: ['**/index.html']
          }
        }
      ]
    })
  ]
}
  1. 測(cè)試環(huán)境webpack.dev.js
const resolveApp = require('./paths')
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

module.exports = {
  mode: 'development',
  devtool: 'cheap-module-source-map',
  // 開發(fā)階段屏蔽 .browserslistrc
  target: 'web',
  // 開啟HMR
  devServer: {
    // 只熱加載變化的部分
    hot: 'only',
    // 開啟壓縮
    compress: true,
    // 處理直接向后端請(qǐng)求,導(dǎo)致404的問題
    historyApiFallback: true,
    proxy: {
      // /info/users
      // http://localhost:4000/info/users
      // https://api.github.com/info/users
      '/info': {
        target: 'https://api.github.com',
        // 重寫
        pathRewrite: { "^/info": "" },
        // 修改host
        changeOrigin: true
      }
    },
    static: {
      // 代表生成的文件在哪兒, 需要output里面publicPath和這里一致
    //   publicPath: '/lg',
      // 我們打包之后的資源如果說(shuō)依賴其它的資源,此時(shí)就告知去哪找。
      // 強(qiáng)烈建議使用絕對(duì)路徑
      directory: resolveApp('./public'),
      // 監(jiān)聽directory
      watch: true
    }
  },
  plugins: [
    // 負(fù)責(zé)讓把具體要使用的插件和webpack結(jié)合起來(lái)
    new ReactRefreshWebpackPlugin()
  ]
}
  1. 根據(jù)環(huán)境配置 babel.config.js
const presets = [
  [
    '@babel/preset-env',
    {
      // false: 不對(duì)當(dāng)前的JS處理做 polyfill 的填充
      // usage: 依據(jù)用戶源代碼當(dāng)中所使用到的新語(yǔ)法進(jìn)行填充
      // entry: 依據(jù)我們當(dāng)前篩選出來(lái)的瀏覽器決定填充什么
      // 使用entry,需要在使用的地方導(dǎo)入頭文件
      // import "core-js/stable";
      // import "regenerator-runtime/runtime"
      useBuiltIns: 'usage',
      // 默認(rèn)版本2
      corejs: 3
    }
  ],
  // 識(shí)別jsx文件
  [ '@babel/preset-react' ],

  // 識(shí)別ts文件
  [ '@babel/preset-typescript' ]
]

const plugins = []
// 依據(jù)當(dāng)前的打包模式來(lái)決定plugins 的值 
const isProduction = process.env.NODE_ENV === 'production'
if (!isProduction) {
  plugins.push(['react-refresh/babel'])
}

module.exports = {
    presets,
    plugins
  }

  1. package.json
"scripts": {
    "build: "tsc --noEmit &&  webpack --config ./config/webpack.common.js --env production",
    "serve": "webpack serve --config ./config/webpack.common.js --env development"
  }
十五、分模塊打包

可以方便加載的時(shí)候,只是加載當(dāng)前需要的模塊,而不是一起都加入到項(xiàng)目中。

  1. 多入口
const commonConfig = {
    entry: {
      main1: './src/main1.js',
      main2: './src/main2.js'
    },
    output: { 
      // filename: 'js/main.js',
      // [name]占位
      filename: 'js/[name].build.js'
    }
  }
  1. 依賴方式
const commonConfig = {
    entry: {
      main1: { import: './src/main1.js', dependOn: 'lodash' },
      main2: { import: './src/main2.js', dependOn: 'lodash' },
      lodash: 'lodash'
      // 同時(shí)依賴多個(gè)
      // main1: { import: './src/main1.js', dependOn: 'shared' },
      // main2: { import: './src/main2.js', dependOn: 'shared' },
      // shared: ['lodash', 'jquery']
    },
    output: { 
      // filename: 'js/main.js',
      // [name]占位
      filename: 'js/[name].build.js'
    }
  }
  1. chunk模式
// webpack.common.js
// webpack 5 自帶
const TerserPlugin = require("terser-webpack-plugin")
const commonConfig = {
    entry: {
      index: './src/index.js'
    },
    optimization: {
      minimizer: [
        new TerserPlugin({
          // 默認(rèn)會(huì)生成一個(gè)注釋文件, 這里去除
          extractComments: false,
        }),
      ],
      splitChunks: {
        // all代表同步和異步加載都分模塊
        chunks: 'all'
      }
    }
}

// 會(huì)生成767.build.js,767是chunkId
  1. splitChunks, 靜態(tài)拆分
splitChunks: {
        // all代表同步和異步加載都分模塊
        // initial代表同步
        chunks: 'initial',  // async initial all
        // 體積大于20KB的進(jìn)行拆分, 而且拆分后最小20KB
        // 一般minSize和maxSize 的值一樣
        minSize: 20000, // 20KB
        maxSize: 20000, // 20KB
        // minSize 和 maxSize優(yōu)先級(jí) 高于 minChunks。
        // 如果要一起使用,就這樣設(shè)置
        // minChunks代表最少import 引用了一次
        minChunks: 1,
        // 處理好了, 先放緩存, 后面處理好了, 再看是否合并
        cacheGroups: {
          // syVendors 和 default 名字隨便定義
          syVendors: {
            // node_modules文件夾里面,代表三方庫(kù)
            // \/代表不同系統(tǒng)里面的路徑符號(hào)
            test: /[\\/]node_modules[\\/]/,
            // filename 可以使用占位符
            filename: 'js/[id]_vendor.js',
            // 優(yōu)先級(jí), 默認(rèn)-10。 數(shù)字越大優(yōu)先級(jí)越高
            priority: -10,
          },
          default: {
            // import 2次的才拆分
            minChunks: 2,
            filename: 'js/syy_[id].js',
            priority: -20,
          }
        }
      }
  1. 動(dòng)態(tài)導(dǎo)入
    動(dòng)態(tài)導(dǎo)入的會(huì)進(jìn)行自動(dòng)拆分模塊
// 動(dòng)態(tài)導(dǎo)入
// 魔法注釋, 會(huì)把title作為chunk的名字
import(/*webpackChunkName: "title"*/'./title')

// webpack.common.js
output: { 
      // 設(shè)置chunk文件輸出名字
      chunkFilename: 'js/chunk_[name].js'
    }, 
    optimization: {
      // natural 按自然數(shù)進(jìn)行編號(hào)排序,如果某個(gè)文件當(dāng)前次不再被依賴那么重新打包時(shí)序號(hào)都會(huì)變
      // named 建議開發(fā)環(huán)境使用,名字長(zhǎng)會(huì)影響性能
      // deterministic 生產(chǎn)環(huán)境使用
      chunkIds: 'deterministic',
      minimizer: [
        new TerserPlugin({
          // 默認(rèn)會(huì)生成一個(gè)注釋文件, 這里去除
          extractComments: false,
        }),
      ]
    }
  1. runtime chunk
    可以將加載模塊的信息抽取出來(lái), 方便做緩存。
    optimization: {
      // 將加載模塊的信息抽取出來(lái),生成一個(gè)新的runtime文件
      // runtimeChunk: true,
      // 同樣的導(dǎo)入信息, 只有一個(gè)runtime
      runtimeChunk: 'single'

      /*其他*/
   }

bundle: 直接部署,入口文件
vendor:三方的庫(kù),node_modules下面
chunk: 依賴代碼塊
runtime:連接信息,方便緩存

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容