portaldacalheta.pt
  • หลัก
  • การจัดการวิศวกรรม
  • บุคลากรและทีมงานของผลิตภัณฑ์
  • อื่น ๆ
  • นวัตกรรม
เทคโนโลยี

รักษาการควบคุม: คำแนะนำสำหรับ Webpack และ React, Pt. 2



ใน ส่วนแรกของบทช่วยสอน React-Webpack นี้ เราได้พูดถึงวิธีกำหนดค่ารถตักและดำเนินการปรับให้เหมาะสม ตอนนี้เราจะพูดถึงเทคนิคขั้นสูงเพิ่มเติมที่เกี่ยวข้องกับกรณีการใช้งานการกำหนดค่า React / Webpack ที่เฉพาะเจาะจง

TypeScript และ React with Webpack: ป้อน Babel

มีหลายวิธีที่คุณสามารถใช้ TypeScript ในไฟล์ ตอบสนอง โครงการ. ในขณะที่ ts-loader เป็นตัวเลือกที่ดีฉันต้องการเน้นไปที่วิธีการแปลงไฟล์ TypeScript โดยใช้ @babel/preset-typescript เนื่องจากไลบรารีจำนวนมากกำลังเผยแพร่ปลั๊กอิน Babel เพื่อดำเนินการเพิ่มประสิทธิภาพเวลาคอมไพล์ นอกเหนือจากการประมวลผลไฟล์ TypeScript แล้วจะช่วยให้เราสามารถใช้ปลั๊กอิน Babel ที่มีให้โดยไลบรารีต่างๆเช่น สไตล์ส่วนประกอบ หรือ react-intl .



สิ่งแรกที่เราต้องทำคือติดตั้ง TypeScript และ Babel dependencies:



npm install -D typescript @babel/preset-typescript @types/react @types/react-dom

จากนั้นเราจะสร้างไฟล์การกำหนดค่า TypeScript โดยใช้โปรแกรมบรรทัดคำสั่ง tsc:



วิธีใช้ sass css
./node_modules/.bin/tsc -init --lib dom --jsx react --isolatedModules

คำสั่งด้านบนจะสร้าง tsconfig.json เหมาะสำหรับการเขียนโค้ดสำหรับสภาพแวดล้อมเบราว์เซอร์ --isolatedModules ตัวเลือกบังคับใช้ข้อ จำกัด บางประการซึ่งทำให้แน่ใจว่ารหัสที่คุณเขียนจะเข้ากันได้ @babel/plugin-transform-typescript . ตัวเลือกนี้มีประโยชน์เพื่อให้ IDE ของคุณเตือนคุณเมื่อคุณเขียนโค้ดในลักษณะที่ Babel จะไม่สามารถแปลงร่างได้

ต่อไปเราจะอัปเดต babel.config.js โดยการแนะนำค่าที่ตั้งล่วงหน้าใหม่:



@@ -6,7 +6,8 @@ module.exports = { modules: false } ], - '@babel/preset-react' + '@babel/preset-react', + '@babel/preset-typescript' ], plugins: [ '@babel/plugin-transform-runtime',

และเปิดใช้งาน .ts นามสกุลไฟล์ใน webpack.config.js:

@@ -11,7 +11,7 @@ module.exports = function(_env, argv) { return { devtool: isDevelopment && 'cheap-module-source-map', - entry: './src/index.js', + entry: './src/index.tsx', output: { path: path.resolve(__dirname, 'dist'), filename: 'assets/js/[name].[contenthash:8].js', @@ -20,7 +20,7 @@ module.exports = function(_env, argv) { module: { rules: [ { - test: /.jsx?$/, + test: /.(js|jsx|ts|tsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', @@ -61,6 +61,9 @@ module.exports = function(_env, argv) { } ] }, + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'] + }, plugins: [ isProduction && new MiniCssExtractPlugin({

การกำหนดค่าข้างต้นเพียงพอที่จะทำให้รหัสของเราสามารถแปลงได้ แต่ไม่สามารถตรวจสอบความถูกต้องได้จริง เราจะต้องทำการตรวจสอบประเภทในกระบวนการแบบขนานแยกต่างหากโดยใช้ fork-ts-checker-webpack-plugin .



ก่อนอื่นเราต้องติดตั้ง:

npm install -D fork-ts-checker-webpack-plugin

จากนั้นเราจะเพิ่มลงใน plugins ส่วนใน webpack.config.js:



@@ -4,6 +4,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); const TerserWebpackPlugin = require('terser-webpack-plugin'); const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); module.exports = function(_env, argv) { const isProduction = argv.mode === 'production'; @@ -78,6 +79,9 @@ module.exports = function(_env, argv) { 'process.env.NODE_ENV': JSON.stringify( isProduction ? 'production' : 'development' ) + }), + new ForkTsCheckerWebpackPlugin({ + async: false }) ].filter(Boolean), optimization: {

การระบุ async: false จะป้องกันไม่ให้ Webpack ปล่อยรหัสที่ไม่ถูกต้องและแสดงข้อผิดพลาดในการคอมไพล์ในโอเวอร์เลย์เมื่อเรียกใช้เซิร์ฟเวอร์การพัฒนา

หมายเหตุ: คุณอาจสนใจ มาโคร Babel ซึ่งกำลังมาแรงอย่างฉุดไม่อยู่



CSS ปรับปรุงผ่าน Webpack

ในบทความก่อนหน้านี้เราได้กล่าวถึงการจัดแต่งทรงผมพื้นฐานโดยใช้ css-loader มีหลายวิธีที่เราสามารถปรับปรุงการกำหนดค่านี้ได้

cfo หมายถึงอะไรในธุรกิจ

การกำหนดค่าที่เสนอจะใช้ประโยชน์จาก โมดูล CSS , Sass และ PostCSS เทคโนโลยี แม้ว่าจะเสริมซึ่งกันและกันในบางวิธี แต่คุณไม่จำเป็นต้องใช้ทั้งหมดในเวลาเดียวกัน การตั้งค่าขั้นสุดท้ายจะเปิดใช้งานปลั๊กอินข้างต้นทั้งหมดและเราจะปล่อยให้คุณไม่ต้องทำอะไรบางอย่างหากคุณมั่นใจว่า“ คุณไม่จำเป็นต้องใช้มัน”



โมดูล CSS

โมดูล CSS แก้ไขปัญหาการกำหนดขอบเขตส่วนกลางในไฟล์ CSS โดยการสร้างชื่อที่ไม่ซ้ำกันแบบสุ่มสำหรับแต่ละคลาส CSS จากมุมมองของไฟล์ JavaScript ที่ใช้โมดูล CSS การเชื่อมโยงระหว่างชื่อคลาสดั้งเดิมและชื่อแบบสุ่มจะแสดงโดยอ็อบเจ็กต์ที่ส่งออกโดยตัวโหลด ช่วยให้คุณค้นหาและใช้คลาสที่ระบุในไฟล์ CSS ในลักษณะที่ทำให้การชนกันโดยบังเอิญแทบจะเป็นไปไม่ได้

การสนับสนุนโมดูล CSS รวมอยู่ใน css-loader แล้ว ตอนนี้เราจะต้องเพิ่มกฎใหม่เพื่อให้ชัดเจนว่า CSS Modules ถูกใช้งานเมื่อใด:

@@ -33,11 +33,25 @@ module.exports = function(_env, argv) { }, { test: /.css$/, use: [ isProduction ? MiniCssExtractPlugin.loader : 'style-loader', 'css-loader' ] }, + { + test: /.module.css$/, + use: [ + isProduction ? MiniCssExtractPlugin.loader : 'style-loader', + { + loader: 'css-loader', + options: { + modules: true + } + } + ] + }, { test: /.(png|jpg|gif)$/i, use: {

ด้วยเหตุนี้ไฟล์ใด ๆ ที่ลงท้ายด้วย .module.css จะถูกประมวลผลโดยเปิดใช้โมดูล CSS

PostCSS

PostCSS เป็นเฟรมเวิร์กการประมวลผล CSS ที่ขยายได้พร้อมไลบรารีปลั๊กอินขนาดใหญ่ที่คุณสามารถใช้เพื่อขยายไวยากรณ์ CSS ทำการเพิ่มประสิทธิภาพหรือจัดเตรียมทางเลือกสำหรับเบราว์เซอร์รุ่นเก่า

ขั้นแรกเราจะติดตั้งการอ้างอิงที่จำเป็น:

npm install -D postcss-loader postcss-import postcss-preset-env

และอัปเดตการกำหนดค่า CSS ของเรา:

@@ -47,9 +47,11 @@ module.exports = function(_env, argv) { { loader: 'css-loader', options: { - modules: true + modules: true, + importLoaders: 1 } - } + }, + 'postcss-loader' ] }, {

เราจะกำหนดค่า PostCSS โดยใช้ปลั๊กอินต่อไปนี้:

  • postcss-import: เปิดใช้งาน PostCSS เพื่อประมวลผล @import งบ
  • postcss-preset-env: ใช้ polyfills เพื่อรองรับคุณสมบัติ CSS ที่ทันสมัยในเบราว์เซอร์ส่วนใหญ่

สร้างไฟล์ชื่อ postcss.config.js และเติมข้อมูลดังต่อไปนี้:

module.exports = { plugins: { 'postcss-import': {}, 'postcss-preset-env': {} } };

คุณสามารถตรวจสอบ ไดเร็กทอรีปลั๊กอิน PostCSS สำหรับส่วนขยายอื่น ๆ ที่คุณอาจพบว่ามีประโยชน์และเพิ่มลงในการกำหนดค่าของคุณ

วิธีทำฟอนต์แบบกำหนดเอง

สัส / วทส

Sass เป็นอีกหนึ่งเฟรมเวิร์กการประมวลผล CSS ยอดนิยม ไม่เหมือนกับ PostCSS Sass มาพร้อมกับ“ แบตเตอรี่ที่มาพร้อมกับ” นอกกรอบ Sass นำเสนอการสนับสนุนสำหรับกฎที่ซ้อนกันมิกซ์อินและกฎการเขียนใหม่สำหรับความเข้ากันได้แบบย้อนหลัง แม้ว่า PostCSS มีจุดมุ่งหมายเพื่อรักษาไวยากรณ์ CSS มาตรฐาน แต่ไวยากรณ์ของ Sass อาจแตกต่างจากข้อกำหนดของ CSS อย่างไรก็ตามเรื่องนี้ Sass เป็นโซลูชันที่แพร่หลายซึ่งการใช้มันสำหรับการเขียน CSS อาจเป็นตัวเลือกที่ง่ายกว่า แต่เป็นวิธีที่ ขึ้นอยู่กับความต้องการของคุณ .

ขั้นแรกเราจะติดตั้งการอ้างอิงที่จำเป็น:

npm install -D sass-loader node-sass resolve-url-loader

จากนั้นเพิ่มตัวโหลดใหม่ในการกำหนดค่า Webpack ของเรา:

@@ -38,6 +38,25 @@ module.exports = function(_env, argv) { 'css-loader' ] }, + { + test: /.s[ac]ss$/, + use: [ + isProduction ? MiniCssExtractPlugin.loader : 'style-loader', + { + loader: 'css-loader', + options: { + importLoaders: 2 + } + }, + 'resolve-url-loader', + { + loader: 'sass-loader', + options: { + sourceMap: true + } + } + ] + }, { test: /.(png|jpg|gif)$/i, use: {

เราได้แก้ไขปัญหาสองสามประการล่วงหน้าเกี่ยวกับตัวอย่างข้อมูลข้างต้น:

  1. เราแนะนำ resolve-url-loader หลัง sass-loader เพื่อให้การนำเข้าแบบสัมพัทธ์ทำงานจาก @import ed Sass files

  2. เราระบุ importLoaders ตัวเลือกสำหรับ css-loader เพื่อประมวลผล @import -ed ไฟล์โดยใช้ตัวโหลดที่ตามมา

    วอร์เรน บุฟเฟ่ต์ ลงทุนอย่างไร

ด้วยการกำหนดค่าข้างต้นเราสามารถเริ่มสร้างสไตล์ของเราโดยใช้ Sass / SCSS นอกเหนือจากโมดูล PostCSS และ CSS ที่เราได้อธิบายไว้ก่อนหน้านี้ แม้ว่าตัวเลือกเหล่านี้ทั้งหมดจะเปิดใช้งานพร้อมกันได้ แต่คุณไม่จำเป็นต้องใช้ตัวเลือกเหล่านี้ทั้งหมดภายในโปรเจ็กต์เดียวกันดังนั้นคุณสามารถเลือกเครื่องมือเดียวที่เหมาะกับความต้องการของคุณมากที่สุด

คนงานเว็บ

คนงานเว็บ เป็นแนวคิดที่มีประสิทธิภาพของเว็บสมัยใหม่ ช่วยให้คุณสามารถลดการคำนวณราคาแพงออกจากเธรดหลักได้ ควรใช้ผู้ปฏิบัติงานบนเว็บเท่าที่จำเป็นและสงวนไว้สำหรับสิ่งที่ไม่สามารถปรับให้เหมาะสมได้โดยการตั้งเวลาอัจฉริยะภายในลูปเหตุการณ์ การใช้ผู้ปฏิบัติงานบนเว็บเป็นตัวเลือกที่ดีสำหรับการเพิ่มประสิทธิภาพการทำงานแบบซิงโครนัสที่ยาวนาน

Webpack ช่วยให้ใช้งาน Web Work ด้วยไฟล์ worker-loader ซึ่งรวมไฟล์ผู้ปฏิบัติงานไว้ในไดเร็กทอรีเอาต์พุตและจัดเตรียมคลาสผู้ปฏิบัติงานให้กับไฟล์ผู้บริโภค

ก่อนอื่นเราต้องติดตั้ง worker-loader:

npm install -D worker-loader

จากนั้นเพิ่มลงในไฟล์กำหนดค่าของเรา:

@@ -31,6 +31,10 @@ module.exports = function(_env, argv) { } } }, + { + test: /.worker.js$/, + loader: 'worker-loader' + }, { test: /.css$/, use: [

ตอนนี้สิ่งที่คุณต้องทำเพื่อเริ่มใช้งานเว็บคือสร้างอินสแตนซ์คลาสที่นำเข้าจากไฟล์ที่ลงท้ายด้วย .worker.js ที่ดำเนินการตามปกติ Worker API .

พนักงานบริการ

พนักงานบริการเปิดใช้งานเทคนิคการเพิ่มประสิทธิภาพขั้นสูงและการปรับปรุงประสบการณ์ของผู้ใช้ ทำให้แอปของคุณทำงานแบบออฟไลน์เมื่อผู้ใช้ขาดการเชื่อมต่อเครือข่าย นอกจากนี้ยังช่วยให้แอปของคุณโหลดทันทีแม้ว่าจะกดอัปเดตแล้วก็ตาม

Webpack ทำให้ง่ายต่อการกำหนดค่าพนักงานบริการสำหรับแอปของคุณโดยใช้ไฟล์ workbox-webpack-plugin โมดูล. ก่อนอื่นเราต้องติดตั้ง:

npm install -D workbox-webpack-plugin

จากนั้นเราจะเพิ่มปลั๊กอินไปที่ plugins ส่วนการกำหนดค่า Webpack ของเรา:

@@ -4,6 +4,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); const TerserWebpackPlugin = require('terser-webpack-plugin'); const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); +const WorkboxPlugin = require('workbox-webpack-plugin'); module.exports = function(_env, argv) { const isProduction = argv.mode === 'production'; @@ -75,6 +76,11 @@ module.exports = function(_env, argv) { 'process.env.NODE_ENV': JSON.stringify( isProduction ? 'production' : 'development' ) + }), + new WorkboxPlugin.GenerateSW({ + swDest: 'service-worker.js', + clientsClaim: true, + skipWaiting: true }) ].filter(Boolean), optimization: {

การกำหนดค่าข้างต้นใช้ตัวเลือกต่อไปนี้:

  • swDest ระบุชื่อไฟล์เอาต์พุตสำหรับไฟล์ผู้ปฏิบัติงานที่สร้างขึ้น
  • clientsClaim สั่งให้ผู้ปฏิบัติงานบริการเข้าควบคุมเพจทันทีหลังจากลงทะเบียนและเริ่มให้บริการทรัพยากรที่แคชไว้แทนที่จะรอให้โหลดหน้าถัดไป
  • skipWaiting ทำให้การอัปเดตโปรแกรมทำงานของบริการมีผลทันทีแทนที่จะรอให้อินสแตนซ์ที่ใช้งานอยู่ทั้งหมดถูกทำลาย

มีเหตุผลที่ดีว่าทำไมตัวเลือกหลังทั้งสองไม่ใช่ค่าเริ่มต้น เมื่อเปิดใช้งานพร้อมกันอาจมีโอกาสเกิด ความบกพร่องที่เกิดขึ้นในสถานการณ์ที่อ่อนไหวต่อเวลา ดังนั้นจึงขึ้นอยู่กับคุณที่จะตัดสินใจอย่างมีสติว่าจะเปิดใช้งานตัวเลือกเหล่านั้นไว้ในการกำหนดค่าของคุณหรือไม่

สุดท้ายเราต้องลงทะเบียนผู้ให้บริการเมื่อผู้ใช้เปิดแอปของเรา:

@@ -2,3 +2,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; ReactDOM.render(

React App

, document.getElementById('root')); + +if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('/service-worker.js'); + }); +}

พนักงานบริการมีความสามารถมากกว่าการเพิ่มความสามารถแบบออฟไลน์ให้กับแอปของเรา หากคุณต้องการการควบคุมพฤติกรรมของพนักงานบริการในระดับที่ดีขึ้นคุณอาจใช้ไฟล์ InjectManifest ปลั๊กอินแทน ด้วยการเขียนไฟล์ผู้ปฏิบัติงานบริการของคุณเองคุณยังสามารถเปิดใช้งานการแคชสำหรับคำขอ API และใช้คุณสมบัติอื่น ๆ ที่พนักงานบริการเปิดใช้งานเช่นการแจ้งเตือนแบบพุช คุณสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับความสามารถของ Workbox ได้ในไฟล์ ส่วนสูตรอาหารขั้นสูงของเอกสารอย่างเป็นทางการ .

Advanced React Webpack Config: ให้โครงการของคุณได้เปรียบ

ส่วนที่สองของชุดบทช่วยสอน Webpack นี้ควรให้ความรู้ที่จำเป็นแก่คุณในการขยายการกำหนดค่า Webpack ของคุณผ่านกรณีการใช้งาน React ทั่วไป ฉันหวังว่าคุณจะพบว่าข้อมูลนี้มีประโยชน์และคุณสามารถขยายการกำหนดค่าส่วนบุคคลของคุณได้อย่างมั่นใจเพื่อให้บรรลุเป้าหมายเฉพาะสำหรับโครงการของคุณ

เช่นเคยคุณสามารถค้นหา ไฟล์คอนฟิกูเรชันที่สมบูรณ์บน GitHub และอ้างถึงไฟล์ เอกสาร Webpack และ ส่วนปลั๊กอิน เพื่อค้นหาสูตรอาหารเพิ่มเติมที่เกี่ยวข้องกับเป้าหมายของคุณ ขอบคุณสำหรับการอ่าน!

ทำความเข้าใจพื้นฐาน

แพ็คเกจ Babel-loader ทำอะไร?

Babel-loader ช่วยให้สามารถประมวลผลไฟล์ JavaScript ที่นำเข้าโดยใช้ Babel และปลั๊กอินต่างๆ

วิธีป้องกันความเสี่ยงจากอัตราแลกเปลี่ยน

Webpack loaders คืออะไร?

ใน Webpack ตัวโหลดระบุกฎสำหรับการประมวลผลไฟล์ที่นำเข้า

ใครเป็นคนสร้าง Webpack?

โครงการ Webpack ก่อตั้งโดย Tobias Koppers ในเดือนมีนาคม 2555 และยังคงได้รับการพัฒนาจนถึงปัจจุบันโดยผู้ดูแลและผู้ให้ข้อมูล Webpack หลายราย

Webpack config คืออะไร?

Webpack config เป็นอ็อบเจ็กต์ JavaScript ที่ระบุกฎสำหรับการประมวลผลอินพุตไฟล์และการสร้างบันเดิลเอาต์พุต

ทำไมจึงใช้ Webpack

Webpack ใช้ในการแปลงรหัส JavaScript ที่ทันสมัยเป็นบันเดิลที่สามารถเรียกใช้งานได้ภายในเบราว์เซอร์

การออกแบบปุ่มในช่วงหลายปีที่ผ่านมา: ไทม์ไลน์ Dribbble

การออกแบบ Ux

การออกแบบปุ่มในช่วงหลายปีที่ผ่านมา: ไทม์ไลน์ Dribbble
Adobe XD เทียบกับ Sketch - เครื่องมือ UX ใดที่เหมาะกับคุณ

Adobe XD เทียบกับ Sketch - เครื่องมือ UX ใดที่เหมาะกับคุณ

การออกแบบ Ui

โพสต์ยอดนิยม
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ
แหล่งข้อมูลสำหรับธุรกิจขนาดเล็กสำหรับ COVID-19: เงินกู้เงินช่วยเหลือและสินเชื่อ
วิธีออกแบบประสบการณ์ที่ยอดเยี่ยมสำหรับอินเทอร์เน็ตในทุกสิ่ง
วิธีออกแบบประสบการณ์ที่ยอดเยี่ยมสำหรับอินเทอร์เน็ตในทุกสิ่ง
กลยุทธ์การสื่อสารที่มีประสิทธิภาพสำหรับนักออกแบบ
กลยุทธ์การสื่อสารที่มีประสิทธิภาพสำหรับนักออกแบบ
เรียนรู้ Markdown: เครื่องมือการเขียนสำหรับนักพัฒนาซอฟต์แวร์
เรียนรู้ Markdown: เครื่องมือการเขียนสำหรับนักพัฒนาซอฟต์แวร์
แนวโน้มต่อไปนี้: การแสดงความเคารพกับการลอกเลียนแบบการออกแบบ
แนวโน้มต่อไปนี้: การแสดงความเคารพกับการลอกเลียนแบบการออกแบบ
 
คู่มือสไตล์ Sass: บทช่วยสอน Sass เกี่ยวกับวิธีการเขียนโค้ด CSS ที่ดีขึ้น
คู่มือสไตล์ Sass: บทช่วยสอน Sass เกี่ยวกับวิธีการเขียนโค้ด CSS ที่ดีขึ้น
ทำลายกระบวนการคิดเชิงออกแบบ
ทำลายกระบวนการคิดเชิงออกแบบ
การออกแบบเว็บไซต์ CMS: คู่มือการใช้งานเนื้อหาแบบไดนามิก
การออกแบบเว็บไซต์ CMS: คู่มือการใช้งานเนื้อหาแบบไดนามิก
ทำคณิตศาสตร์: การปรับขนาดแอปพลิเคชันไมโครเซอร์วิสด้วย Orchestrators
ทำคณิตศาสตร์: การปรับขนาดแอปพลิเคชันไมโครเซอร์วิสด้วย Orchestrators
การปฏิวัติหุ่นยนต์เชิงพาณิชย์ที่กำลังจะเกิดขึ้น
การปฏิวัติหุ่นยนต์เชิงพาณิชย์ที่กำลังจะเกิดขึ้น
โพสต์ยอดนิยม
  • ใช้ Bootstrap สร้างเว็บไซต์
  • เริ่มต้นกับ angular js
  • วิกฤตการณ์ทางการเงินของกรีกสำหรับหุ่น
  • บัตรเครดิตถูกแฮกด้วยยอดเงินคงเหลือ 2020
  • เอ็นจิ้นฟิสิกส์ c++
  • วิธีการทำมอนติคาร์โลจำลอง
หมวดหมู่
  • การจัดการวิศวกรรม
  • บุคลากรและทีมงานของผลิตภัณฑ์
  • อื่น ๆ
  • นวัตกรรม
  • © 2022 | สงวนลิขสิทธิ์

    portaldacalheta.pt