从 CDNs 到 Bunbling 更新您的前端建设管道@ : @%
一. 导言导言 导言 导言 导言
在过去的一年里, “, I' 跌倒”“, 实验 , 破碎了东西’, 并逐渐将这个博客的前端建设管道“ MS K5 ” 现代化。 这是' 一些执行的总计划完美无缺地— 它是一个试验和错误, 许多差错", 以及顽固不化的坚持力 驱动着一个清晰的愿景:我想要实现什么?.
I'm 不是一个前端导师或Webpack 向导@. I @'m a NET开发商,他对基于 CDN}-的附属关系的限制感到沮丧,决定必须有一个更好的方法_.}这篇文章记录了从简单开始的乱七八糟的 , 迭接旅程。 <script> 指向一个能实际工作的现代捆绑管道的无千克标记@. @%
在“(”的路上,我犯了许多错误。 IQ'll Document “),花了几个小时去解答加密网页卡误差@,,可能还会重整 node_modules 超过我愿意承认的几倍... ...但坚持有回报...",...
如果您是 're a {.}NET 开发者, 盯着 Webpack 配置文件看... ...想知道你在地球上得到了什么?
I'm 是一个老式的网络性能螺旋管 , 拨号@-\上第一个我为赚钱而建的站点 @(}这是在Perlç...a故事中的色情后端
在那段时间里,人们所担心的与众不同的是 @. JavaScript几乎无人知晓$.}我想即使是Divs也是在IE那年代 div 网景 layer)和您'dluckY 如果您的用户有一个 @56K连接@.}所以我学会了最优化的 @MS K4_even things like tilled imageformation front for m菜单项 @)}等等#...}
后来在微软,我甚至工作了一个自动图像图示工具 在Web Front 表格 @-} 它从一个页面“,”中提取了小的图片。它生成了CSS和一幅图象 自动地.}但是就像我在 Microsoft@,}那样
简而言之,没有人喜欢一个缓慢的网页@! @
公平@,}CDNs aren't neither disality #. * CDN是天生邪恶的#'*
充分披露@:_#这个博客是故意设计过度的@.}它确实如此 't 需要 虽然如此复杂 但这样建起来 让我好好学习现代前端工具 关键地说 , 和\ MSSK2 给了我一些真实的东西 可以写作并教书
CDN 的问题
起初我的方法很直截了当
<!-- Old CDN-based approach -->
<script src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
<script src="https://unpkg.com/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.css">
虽然这工作有好几种缺点 越来越令人沮丧
- 可靠性问题:CDNs do gon down@.~I' 看过unpkg和jsdelivr有误差 当他们"'re dolown}♪,你的网站被打破了
- 难以预测的装载行为: @ CDN 回应可能变幻无常, 有时变快@._ 有时变慢#,}有时减慢 @,}有时候它们引入种族环境, 让图书馆按错误的顺序负荷
- 时间安排问题: 你无法控制脚本在彼此相邻时的负荷@. 这让我对图书馆初始化感到无尽头痛
- 多重HTTP请求“: ” 每个图书馆都要求单独申请“, ” 即使有 HTTP ” “MSSK2 ”
- 无树-摇晃: 你下载整个库 *, 即使你只使用其中的一小部分
- 版本流动: CDNs 可能提供不同的版本, 除非您明确指定它们@,, 甚至被钉住的版本也可以在 CCDN 提供者中表现不同 。
- 构建-时间不确定性@:_# 无法在运行前发现不兼容性@—}经常当用户报告它的时候
- 有限优化:Can't 破解或移除死代码
- 离线发展在火车或飞机上工作时很烦人。
所以我想要控制我的网站使用和需要的正确位置 来控制我的工作。 我想只捆绑 我需要的东西 确保可靠的装货订单\MSK
他们更简单地设置了“,”和“HTTP/2 ”及“ HTTP/3 +多倍驱动”、“, + ”,对于许多项目来说,多重请求的间接费用比以前 “.”要重要得多。
现代捆包办法
我目前设置的套件包通过 Webpack 将所有 JavaScript 依赖性都包含在网上, 通过 PostCSS @ . 处理 CSS
为什么Webpack 取代 Vite? @
在潜入技术细节前 ",#我应该先谈谈房间里的大象 ':> '为什么我在使用Webpack 当Vite',#rollup #,_Esbuilding,}和其他现代包装机存在时
诚实的回答很简单, 我早就知道网包.
I'd在教授我的“"Beginning Web Development”时广泛使用Webpack@"课程,}这是我理解的.的工具 当我决定把这个博客现代化的时候..."'s building proper*,I 已经面对着一个陡峭的学习曲线\—{Odeaddocation tree+-shakingMS K9代码分割 “,模块系统_, PostCSS输油管,和如何将所有这一切与 ASPQ.NET Core整合
在项目工作时,它通常是一种良好做法。 将“'”限制在 “'”管理@'.”的范围内。
添加一个全新的建筑工具@" @% 除此之外,我还可以把学习的能量集中到 概念概念 而不是某种工具的特异性....
是Vite 更快@? @ “绝对”.Vite's开发服务器,使用本地的ES模块和 esbuilding-phown 捆绑比WebpackMPK3要快得多。对于有数百个模块的大型项目来说,“,”差别非常大。
您应该使用 Vite 进行新工程@? @% 可能是,@ 是 @ . @ 如果您在开始更新, 而且没有现有的网页卡知识 @ I, @ Vite 很可能是更好的选择@ MS K5 @ It' @ server@ MPK7_ 比较简单来配置\ ,} 并代表着前端工具的现代方法 @. @
我后悔使用Webpack@? 我学到的关于Bunbling, 代码分裂的教训 和优化可以转移到任何建筑工具. 而诚实地说, 对于这个博客来说 这个网络软件包与维特之间的性能差异微乎其微
它是我如何建造东西的关键方面 ;,以什么为起点 从这个基础出发
这里更广泛的教训是 进度胜于完美我本可以花几周时间研究“"Best}"Baglyr,}比较基准@,阅读比较文章, 和对决定的煎熬
或许有一天我可能会移居到Vite., 也许我能赢'tMS K2 任何一种方式,这个博客有一个现代的#,优化建材管道,可以可靠地工作\—,而且这“'}什么重要?.
软件包结构
缩略 package.json 这个结构花了我几次尝试去右转\ — 最初 , Nuget和 npm是 KINDA 相似的, 但是 nppm 在添加 pacakkes\ MPK3\ 时则不太友好
{
"dependencies": {
//NOTE - This is a pre-release of these enhancements, the 1.0.0 release is OUT NOW!
"@mostlylucid/mermaid-enhancements": "^1.0.0-alpha0",
"alpinejs": "^3.14.1",
"codemirror": "5.65.13",
"core-js": "^3.39.0",
"easymde": "2.20.0",
"flatpickr": "^4.6.13",
"highlight.js": "^11.10.0",
"highlightjs-cshtml-razor": "^2.1.1",
"html-to-image": "^1.11.13",
"htmx.org": "^2.0.1",
"mermaid": "^11.0.2",
"regenerator-runtime": "^0.14.1",
"svg-pan-zoom": "^3.6.2"
},
//These are just used for build; not needed to RUN the app so we have a separate place for 'em
"devDependencies": {
"@babel/core": "7.26.9",
"@babel/preset-env": "7.26.9",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.12",
"autoprefixer": "10.4.21",
"babel-loader": "10.0.0",
"cpx": "1.5.0",
"css-loader": "7.1.2",
"cssnano": "7.0.6",
"daisyui": "^4.12.10",
"mini-css-extract-plugin": "^2.9.4",
"npm-run-all": "4.1.5",
"postcss": "8.5.3",
"postcss-cli": "11.0.1",
"postcss-import": "^16.1.0",
"rimraf": "6.0.1",
"style-loader": "4.0.0",
"tailwindcss": "3.4.17",
"terser-webpack-plugin": "^5.3.10",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
}
依赖性 运行时需要图书馆@( @Allpine.}{js @,}HTMX},}EasyMD_,}等 发展依赖性 正在构建工具@( @Webpack_,}babyl,}邮局CSS处理器{,}等 .).
构建脚本
缩略 package.json 脚本已显著进化@ : @
{
"scripts": {
"clean": "rimraf ./.tmp ./wwwroot/css/dist ./wwwroot/js/dist",
"copy:static": "cpx \"src/css/{raleway,easymde-overrides}.css\" \"wwwroot/css/dist\"",
"copy:highlight": "cpx \"src/css/highlight/*.min.css\" \"wwwroot/css/highlight\"",
"copy:all": "npm-run-all --parallel copy:static copy:highlight",
"copy:watch": "cpx \"src/css/{raleway,easymde-overrides}.css\" \"wwwroot/css/dist\" --watch & cpx \"src/css/highlight/*.min.css\" \"wwwroot/css/highlight\" --watch",
"tw:dev": "postcss ./src/css/main.css -o ./wwwroot/css/dist/main.css",
"tw:prod": "postcss ./src/css/main.css -o ./wwwroot/css/dist/main.css --no-map --verbose",
"tw:watch": "postcss ./src/css/main.css -o ./wwwroot/css/dist/main.css --watch",
"js:dev": "webpack --env development",
"js:prod": "webpack --mode production",
"js:watch": "webpack watch --mode development",
"dev": "npm-run-all clean --parallel copy:all tw:dev js:dev",
"watch": "npm-run-all clean copy:all --parallel copy:watch tw:watch js:watch",
"build": "npm-run-all clean copy:all --parallel tw:prod js:prod"
}
}
此设置区分了关注的事务 @: @%
- 清洁: 删除先前使用过的构建输出
rimraf - 复制@: @%* 任务@ : @ 复制静态 CSS 文件, 它们需要处理 MS K1} @ ( @ 这些要么是 @ I'_ imports @ MPK4} 用于某种特殊目的, 比如装入我的滑稽兰威字体, 要么是适应性字型, 如主题切换增强. Name
- {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}我* 通过 PostCSS 处理尾风 CSS 任务
- {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}我* 通过Webpack 完成的任务@ : bundles JavaScript
- Dev / 观察 MS K1 建设: 管弦化整个管道
缩略 npm-run-all 软件包启用了用于快速建设的平行执行@. @%
您可以设置 npm run build 在本地建设期间自动运行,但对于 CI &(}您需要确保它“'”等功能被禁用。 @).}
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<SpaRoot>ClientApp\</SpaRoot>
</PropertyGroup>
<!-- Run npm install only when package.json changes -->
<Target Name="NpmInstall" Inputs="$(SpaRoot)package.json" Outputs="$(SpaRoot)node_modules" BeforeTargets="Build">
<Message Importance="high" Text="Running npm install in $(SpaRoot)" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm ci" />
</Target>
<!-- Run npm build before the .NET build -->
<Target Name="NpmBuild" DependsOnTargets="NpmInstall" BeforeTargets="Build">
<Message Importance="high" Text="Running npm run build in $(SpaRoot)" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
</Target>
</Project>
要做到这一点,只需在您的 csproj... 中添加此内容。 您甚至可以说只在调试期间运行@ ' 等 @ MS K2 @ 但我发现它乱七八糟的 @ MPK3 @ 我宁愿手动运行@. @ 所以 npm run watch 当任何 cs /}js 文件更改为自动\ I-}* 正在运行构建 *\ MPK3}
在JS世界里,他们几乎使用热的-reload dev runs 这是相当滑稽并让你有点讨厌ASP}.NET Core{'}这些微弱的尝试 *.}
Webpack 配置深潜水
网络软件包的配置是魔法发生的地方 @—#和大部分时间我花在排除故障上的地方@.}这曾经是't春天完全成型的.} It'}由于无数次迭代的结果,}Stack overflow search>,}和通过网页软件包文件读取, 在“2+AM”试图理解为什么我的建筑正在生成 &47}块文件
这里“ '” 是当前配置@ MS K1 from webpack.config.js“)”详细解释了每个部分的工作内容和原因,
const TerserPlugin = require('terser-webpack-plugin');
const path = require('path');
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
mode: isProduction ? 'production' : 'development',
entry: {
main: './src/js/main.js',
},
output: {
filename: '[name].js',
chunkFilename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'wwwroot/js/dist'),
publicPath: '/js/dist/',
module: true,
clean: true,
},
experiments: {
outputModule: true,
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', {
targets: '> 0.25%, not dead',
modules: false,
useBuiltIns: 'usage',
corejs: 3,
}],
],
},
},
},
],
},
resolve: {
extensions: ['.js', '.mjs'],
alias: {
'@mostlylucid/mermaid-enhancements$': path.resolve(__dirname, 'node_modules/@mostlylucid/mermaid-enhancements/dist/index.min.js')
}
},
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 100000,
name: false,
},
runtimeChunk: {
name: 'runtime',
},
minimize: isProduction,
minimizer: isProduction ? [
new TerserPlugin({
terserOptions: {
ecma: 2020,
compress: {
drop_console: true,
passes: 3,
toplevel: true,
pure_funcs: ['console.info', 'console.debug'],
},
mangle: {
toplevel: true,
},
format: {
comments: false,
},
},
extractComments: true,
}),
] : [],
},
devtool: isProduction ? false : 'eval-source-map',
performance: {
hints: isProduction ? 'warning' : false,
}
};
};
解释的密钥配置区域
代码分割和弹出
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 100000,
name: false,
},
runtimeChunk: {
name: 'runtime',
},
}
此配置自动将您的代码分割成小块@ : @
- 块@: @ @ @ '} 全部 @ MPK2 @“:”分析同步进口和非同步进口
- 秒=:} @ 20000: 仅为大于 @20}KB 的模块创建块
- 最大Size=:=100000=“:”试图分割大于“100”的块
- 运行时间 chunk: 提取 Webpack 时间运行到一个单独的文件, 用于改进 longQ-term caching
在 @ ,} 这将生成多个文件 wwwroot/js/dist/:
main.js-您的申请入境点runtime.js-Webpack 模块装入逻辑[vendor].[contenthash].js- 自动分割销售商块- 代码% - @split 路径或懒惰@-}装入模块的额外块块
婴儿出生
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', {
targets: '> 0.25%, not dead',
modules: false,
useBuiltIns: 'usage',
corejs: 3,
}],
],
},
},
}
支持旧浏览器的现代 JavaScript+@:
- 具体目标指标目标: 支持浏览器, 其市场份额仍然维持着 @>0.25%
- 模組@: 假:PreservesES6_BARBAR_Webpack tree-_shaking 的模块
- 使用 InbuiltIns@ : @\ MS K1_ usage @ ': 自动包含只针对您使用的特性的多填充量
- 核心Js: 3:使用核心@-js 版本 @3用于多填充
这意味着我可以写现代 JavaScript @ ( @ async@ MS K1 @ wait,_ 任选链条 @ MPK3} 完全无效的联结=)}同时保持广泛的浏览器支持@.}
生产最集中化
minimizer: isProduction ? [
new TerserPlugin({
terserOptions: {
ecma: 2020,
compress: {
drop_console: true,
passes: 3,
toplevel: true,
pure_funcs: ['console.info', 'console.debug'],
},
mangle: {
toplevel: true,
},
format: {
comments: false,
},
},
extractComments: true,
}),
] : []
Terser 积极将生产规模放大,
- 左下方@__%Contol: 全部删除
console.log()报表报表 - {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}Massós: 3: 运行压缩三次以最大尺寸减小
- 最上层@: @ 真实: 曼格勒斯顶端 @-}等級變數名稱
- 纯_funcs: 移除特定的控制台方法, 即使指定为变量
- @:_# 虚假的评论: 勾销输出的所有批注
与未校正的代码@.相比, 这通常会减少 JavaScript 捆绑大小 。
PSCSS 尾风管道
尾风 CSS 由 PostCSCS 用多个插件处理, 此配置为 @ (} 来自 postcss.config.js与Webpack和:相比,
// postcss.config.js
module.exports = {
plugins: {
'postcss-import': {},
tailwindcss: {},
autoprefixer: {},
cssnano: { preset: 'default' }
}
}
管道工程如下:
- 进口*:* 决心
@importCSS 文件中的语句 - 尾风: 处理尾风指令并生成工具类
- 自动前缀器: 添加用于浏览器兼容性的供应商前缀
- 丙诺: 最小化 CSS 最后输出
尾风配置
缩略 tailwind.config.js 查找类名@ . @ 获取 content 右侧是关键路径 @— miss a path and Tadwind won@'}%t 为这些文件生成分类 *\ :}
module.exports = {
content: ["./Views/**/*.cshtml", "./EmailSubscription/**/*.cshtml"],
safelist: ["dark", "light"],
darkMode: "class",
theme: {
fontFamily: {
body: ["Raleway", "sans-serif"],
},
extend: {
colors: {
"custom-light-bg": "#ffffff",
"custom-dark-bg": "#1d232a",
primary: "#072344",
secondary: "#00aaa1",
// ... more custom colours
},
},
},
plugins: [
require("@tailwindcss/aspect-ratio"),
require("@tailwindcss/typography"),
require("daisyui"),
],
};
密钥特性 @:
- 内容内容内容:扫描
.cshtml包括 Razor 视图和电子邮件模板@)} - 安全列表: @% 总是包含这些类, 即使扫描中找不到它们 。
- 黑暗的Mode: @\ "}=类@"#: 启用类@-基暗模式切换
- 主题@. @% extend添加自定义颜色和间距值
- 插件插件: 包括尾风插件和 DisaiUI 组件库
在构建时间时反尾风扫描这些文件@ , @ 仅提取您实际使用的工具类 MS K1} 这就是为什么最终的 CSS 文件比完整的 Tailwind 库要小得多吗?
JavaScript 进入点
缩略 main.js 此文件的导入和初始化全部依赖性@ , @ 和它='$%s 有机地成长为 I'+# 已添加了博客功能\ MS K4}
// src/js/main.js
import hljsRazor from "highlightjs-cshtml-razor";
import mermaid from "mermaid";
import Alpine from 'alpinejs';
import htmx from "htmx.org";
import hljs from "highlight.js";
import EasyMDE from "easymde";
import 'easymde/dist/easymde.min.css';
import flatpickr from "flatpickr";
import 'flatpickr/dist/flatpickr.min.css';
// Expose libraries globally for Razor views
window.Alpine = Alpine;
window.hljs = hljs;
window.htmx = htmx;
window.mermaid = mermaid;
window.EasyMDE = EasyMDE;
window.flatpickr = flatpickr;
// Import custom modules
import { typeahead } from "./typeahead";
import { submitTranslation, viewTranslation } from "./translations";
import { codeeditor } from "./simplemde_editor";
import { globalSetup } from "./global";
import { comments } from "./comments";
// Attach to namespace
window.mostlylucid = window.mostlylucid || {};
window.mostlylucid.typeahead = typeahead;
window.mostlylucid.comments = comments();
window.mostlylucid.translations = {
submitTranslation: submitTranslation,
viewTranslation: viewTranslation
};
// Initialise Alpine
Alpine.start();
这种方法可带来若干好处*:
- 单一进口点: 所有从一个条目文件装入的依附关系
- 公开文本@ :_ profile@ MS K1}json 锁定特定版本
- 树木@-_shaking:Webpack 从图书馆移除未使用的代码
- 全球接触由 Razor 浏览的 M:图书馆
window - 自定义模块:應用程式@- 特定代码已整理成可导入模块
布局模板集成
内 _Layout.cshtml@,_i 现在只引用已捆绑的资产@:}
<head>
<link href="/css/dist/main.css" asp-append-version="true" rel="stylesheet" />
</head>
<body>
<!-- Content -->
<script src="~/js/dist/main.js" type="module" asp-append-version="true"></script>
</body>
附注一具体说明 module 以让浏览器知道 JS 文件的类型。 这是 @ & @ asp-append-version 一个整洁的小 ASP.NET 标签助手, 该助手将文件内容的散列版本附加到查询中@ ; 有效缓存 @ MS K2busting
仅剩的CDN依赖关系是:
- Google 签名@- @in: 需要外部 CDN 的 OAUT 功能
- 反盒式: 图标字体 @( 可以捆绑@, 但最小的收益)
- Umami分析器@ : Third-party 分析脚本@-自我主机, 这样我就能看到你的访问而不是谷歌 @??
构建管道可视化
整个建设过程如何从源文件流向生产资产?
graph TD
A[Source Files] --> B[npm run build]
B --> C[Clean Task]
C --> D[rimraf wwwroot/css/dist wwwroot/js/dist]
B --> E[Copy Task]
E --> F[cpx: Copy static CSS files]
F --> G[wwwroot/css/dist/raleway.css]
F --> H[wwwroot/css/dist/easymde-overrides.css]
B --> I[Tailwind Task]
I --> J[PostCSS Pipeline]
J --> K[postcss-import]
K --> L[Tailwind CSS]
L --> M[Autoprefixer]
M --> N[cssnano]
N --> O[wwwroot/css/dist/main.css]
B --> P[Webpack Task]
P --> Q[Entry: src/js/main.js]
Q --> R[Babel Transpilation]
R --> S[Module Resolution]
S --> T[Tree Shaking]
T --> U[Code Splitting]
U --> V[Terser Minification]
V --> W[wwwroot/js/dist/main.js]
V --> X[wwwroot/js/dist/runtime.js]
V --> Y[wwwroot/js/dist/vendor chunks]
O --> Z[ASP.NET Core Static Files]
W --> Z
X --> Z
Y --> Z
G --> Z
H --> Z
Z --> AA[Browser]
style A stroke:#0ea5e9,stroke-width:3px
style Z stroke:#f59e0b,stroke-width:3px
style AA stroke:#10b981,stroke-width:3px
它看起来相当复杂,但实际上它处理大部分的网络 Pack does @,}这本身就是一种复杂的方式。 象Vite Don@'这样的人需要这种复杂的方式... ...但是.. ) *
业绩改进
重覆, 并不是真的 PONINT. 但它的确像一个绝对子弹一样载荷 现在 . 您仍然可以得到与云层的争议
开发者经验收益
现代建筑管道大大改进了发展工作流程 :
安全类型和 Intelli 感知
通过Webpack捆绑使适当的 JavaScript 模块解析 ,}意思是:
- VS 代码中的 Intelli 感知:Auto-完成导入模块的补全
- 跳转到定义: 导航直接到图书馆源代码
- 内线文件图书馆的JSDoc评论出现在IDE上。
当建筑破裂时 npm run watch“) ”我知道Instantly@, 与“(”相结合,
热模块替换
发展期间*, npm run watch 启用“ 近端”\ - @ instant 回馈@ MS K1} {
npm run watch
此功能在监视模式下运行 Webpack@ , @ 重建只更改了模块@ I:}
- 典型重建时间*: 200-400*
- 浏览器自动@ - @ refresh使用浏览器@- @sync 或类似工具
- 预先保留的申请状态@:_HMR维持申请状态,
扶养管理
npm's 锁定文件 @ (package-lock.json)+#确保环境的一致建设 #:+#
npm ci # Clean install from lock file
这保证了在开发中 , CI/CDMS K2和生产环境中的同一依赖性版本@.
在JSWorld_,}这些被称为“'pinning' ” JS WORLA中,依附关系设置在 Stone@.}您可以不用软件包锁做,但随后您也可以不使用软件包锁定。
构建脚本
组织起来的 npm 脚本使共同的任务变得容易@: @%
npm run dev # One-time development build
npm run watch # Continuous development builds
npm run build # Production build with optimisations
npm run clean # Remove build artefacts
共同模式和解决办法
全球全球博览馆
有些图书馆需要全球曝光,以便用于 Razor 视图或内线脚本@: @%
// Make library available globally
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
然后在 .cshtml 文件 *% 1}
<div x-data="{ open: false }">
<!-- Alpine.js works because it's on window -->
</div>
从 JavaScript 模块处理 CSS
有些图书馆包括需要导入的 CSS@: @%
import EasyMDE from "easymde";
import 'easymde/dist/easymde.min.css'; // Imported CSS is processed by Webpack
Webpack+' @%s css-loader 和 style-loader 处理这些导入的“% 1”
- CSS 在建造期间提取
- 通过电子邮件输入页面
<style>标签或单独的 CSS 文件 - 自动前置和最小化
懒惰装货重型图书馆
使用动态导入@:
// Only load Mermaid when needed
async function initMermaid() {
const mermaid = await import('mermaid');
mermaid.default.initialize({ startOnLoad: true });
}
// Call when needed
if (document.querySelector('.mermaid')) {
initMermaid();
}
Webpack 自动代码@ - @ splits 将动态导入为单独的块@ MPK1} 已装入 MS K2{ 点名} .} 。
处理共同JS模块
一些较老的图书馆使用共同JS, 而不是ES6+#模块@:+%
// CommonJS require syntax
const hljs = require('highlight.js');
// Or use dynamic import
import('highlight.js').then(hljs => {
// Use hljs
});
Webpack 以透明的方式操作两个模块系统@ , @ 将 CompicJS 转换为ES @ MS K1}( 需要时)\ .
解决共同问题
发展过程中缺少的原始地图
确保确保: devtool 被配置在 webpack.config.js:
devtool: isProduction ? false : 'eval-source-map',
这将生成源地图, 以便更容易调试@. @%
CSS 与尾风的分类净化问题
如果尾风删除课程, 您将使用 @ , check content 配置@: @%
// tailwind.config.js
module.exports = {
content: [
'./Views/**/*.cshtml',
'./Components/**/*.cshtml',
// Add any other paths where classes are used
],
}
使用“Open,” safelist 用于动态类@: @%
safelist: [
'bg-blue-500',
'text-red-600',
{
pattern: /bg-(red|green|blue)-(400|500|600)/,
}
]
模块未找到错误
如果 Webpack 能解答一个模块 @ , check@ MS K2 t
- 校正导入路径@ :_ 相对路径开始于
./或../ - 文件扩展名“: 添加”
.mjs至resolve.extensions必要时 - 异式: 使用
resolve.alias复杂路径
resolve: {
extensions: ['.js', '.mjs', '.json'],
alias: {
'@components': path.resolve(__dirname, 'src/js/components/'),
}
}
建设绩效问题
如果建筑变慢了 :
- 启用缓存:+Webpack @'QS 缓存大大加快了重建的速度
- 减少贝贝范围\ :\ 在 Babel 处理中排除更多目录@ action
- 升级工具“:”新版本的网页包和 Babel 更快。
- 平行建设: 使用
thread-loader用于多@ - @ threaded 移植
// Enable Webpack caching
cache: {
type: 'filesystem',
},
A. 汲取的艰难经验教训
让我分享一下我在这段旅程中犯的一些错误,
试图同时包扎一切
我的第一个尝试是将所有CDN参考文件一一撕开, 并试图通过Webpack@.+#这栋建筑破碎得惊人地打破了.+_我了解到,递增迁移是你的朋友\—+%移动一个图书馆 一次彻底的,+测试,}然后移到下一个#.+#
不理解模块类型
我浪费了几个小时 试图弄清楚为什么某些图书馆 会"'t load.}结果发现"MS K2混合共同JS (require()“)”和“ESZ6”模块“(”import@)_# 不懂Webpack如何操作它们导致加密错误@.} experiments: { outputModule: true } 我初始设置中的配置@ ' @ title
解决之道来自午夜时分在Webpack仓库读取GitHub议题,
错误@#3: @ 超过% - @ 侵略性代码分割
在某一点, 我的配置正在为我拥有的一切 创造块子 minSize: 10000 (10KB) 意思是Webpack正在为小型通用功能创建单独的文件 @. 校正过@- 并被修改到 @MS K4MBMZ}...Page 负载成为“50+小块请求”的瀑布或等待大块下载.我学到了代码分割是好的@,,但你需要明智的阈值#.那"'}为什么我的当前配置使用 minSize: 20000 # (20KB).#
忘记了 .mjs 延长
一些 npm 软件包配有 .mjs 扩展@. @ webpack won'}t 默认解答这些... @.}我花了很尴尬的很长时间调试为什么 @mostlylucid/mermaid-enhancements 在发现我需要添加前 't 加载 .mjs 至 resolve.extensions.
简单修正一旦您知道它@, @ but finding that out"?}但发现它花费了时间#.}
错误% 1\ #5:\
“30-60”秒后开始早期建造“MSK 0 秒”,因为我曾经启用过Webpack@' 文件系统缓存@MS K3 一旦我添加了 caching, 重建时间滴落到 @2-3 second_ . 这是用于开发工作流程的游戏‘- changerr, 但花了我几周才发现.}
我实际使用的尾风净化类
我最喜欢的调试经验... ...:CSS课程,这些课程在发展中表现良好 在制作过程中突然消失 safelist 配置@,}但只是在 I' 浪费了时间之后... ...想知道我是否要疯了吗?
我同样也 ( 例如 mostlylucid.pagingtaghelper Project )使用 @'dommy block@'}我通过隐藏块来简化我的尾风配置更改
<!--
Preserve Tailwind & DaisyUI classes used in embedded pager views.
Without this, TailwindCSS tree-shaking removes classes from the embedded library views.
-->
<span class="hidden
btn btn-sm btn-active btn-disabled join join-item badge badge-sm select select-bordered select-sm label label-text
px-3 py-2 py-1 text-sm font-medium border rounded whitespace-nowrap cursor-not-allowed
text-gray-700 text-gray-600 text-gray-400 text-white bg-white bg-gray-100 bg-blue-600 border-gray-300 border-blue-600
hover:bg-gray-50 hover:bg-blue-700
dark:bg-gray-800 dark:bg-gray-700 dark:bg-blue-500 dark:text-gray-300 dark:text-gray-500 dark:text-gray-200
dark:border-gray-600 dark:border-blue-500 dark:hover:bg-gray-700 dark:hover:bg-blue-600">
</span>
当尾风建立时, 它扫描了类的 cshtml 文件@ ; @ 如果它不这样做的话, 它会删除它们 '} 所以如果这个隐藏区块可以确保它看到我所需要的类别 即使它们只在嵌入的库视图中使用 're.}JSP开发商通常也会扫描 JS/TS 文件以便使用 CSS 样式来让 Talwind 否则将会错过 &.}
module.exports = {
content: ["./Views/**/*.cshtml", "./EmailSubscription/**/*.cshtml"],
-//^^^^ This is what Tailwing knows where to look for classes duritng the tree Shake.
+//^^^^ This is what Tailwind knows where to look for classes during the tree-shake.
...
future: {...}
}
@,@ ' 塔林风批准}'_ 策略是将课程添加到安全列表中, 但I'{ 是一个 ASP=.NET gate_ MS K6}所以 HTML won.}
我得到了正确的 : 持久性
我做对的一件事就是拒绝放弃. 所有错误信息都是一个学习机会 . 每一个破碎的建筑都教给我一些关于这些工具如何运作的新东西 '.我有一个清晰的愿景—bundled," 最佳资产,快速装载"MS K5" 直到我到达那里为止 我一直不停地重复
结论结论
从CDNMSMK0基依赖性向现代捆绑管道的移动已经对这个博客“,”产生了转变,但表现上的改进是巨大的 “'t easy”.。
密钥取走@: @%
- 捆绑减少有效载荷体大小@ : @ 树木@ MS K1_ shaking and minfication 取消未使用的代码
- 代码分割会改善业绩: 浏览器只装载需要的东西
- 构建工具启用现代 JavaScript:Babel传译支持最新的语言功能,同时保持浏览器兼容性。
- CSS 中央支助: 尾风@' JIT 编译器和 csnano 提供小样式表
- 与 @.NET的整合是无缝的: MSBulild 目标自动运行前端建筑
- 持久性胜过完美{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你需要做前端专家
对于习惯于简单 CDN 的 ASP.NET核心开发商来说, 包括{,} 这在一开始会感到压倒性不已: <MSK23#s normal_.}我同样感觉到 . start small\MS K6 一次迁移一个受抚养人@, 并且不要害怕破坏发展过程中的东西〞%.你□' 会从调试破碎的建筑中学中学到更多东西 比你看文档时要多得多吗.
在此共享的配置 I' @ ve 表示几个月的循环@ . @ 您的旅行将会不同 @ MS K2 @ 并使用此选项作为起始点 @ MPK5 @ not gospel}.{ 调整它以适应您的需要 @ MEK7_ 实验=, 并且不要因为失败而感到沮丧\ — @ itemez@'}这是进程的一部分 @.}
这个博客是否设计过周密 @?@ 绝对的.我能不能继续使用CDN(CDN)并花时间做其他事?
如果您仍然依赖 CDN 作为您的前端依附关系 我鼓励您用一个库来捆绑尝试. . 看看它从那里感觉到什么"MS K4" Iterate.}生态系统已经大大成熟了 虽然学习曲线是真实的, 但报酬值得