惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
雷峰网
雷峰网
Recent Announcements
Recent Announcements
月光博客
月光博客
G
Google Developers Blog
腾讯CDC
S
Secure Thoughts
大猫的无限游戏
大猫的无限游戏
T
Tenable Blog
云风的 BLOG
云风的 BLOG
W
WeLiveSecurity
博客园 - 【当耐特】
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 聂微东
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
P
Privacy International News Feed
MyScale Blog
MyScale Blog
K
Kaspersky official blog
T
The Blog of Author Tim Ferriss
Attack and Defense Labs
Attack and Defense Labs
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
aimingoo的专栏
aimingoo的专栏
I
Intezer
Vercel News
Vercel News
小众软件
小众软件
Simon Willison's Weblog
Simon Willison's Weblog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
N
Netflix TechBlog - Medium
P
Proofpoint News Feed
Latest news
Latest news
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tor Project blog
S
Security Affairs
P
Proofpoint News Feed
博客园 - 三生石上(FineUI控件)
博客园 - Franky
C
Cyber Attacks, Cyber Crime and Cyber Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
美团技术团队
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
Security @ Cisco Blogs
L
LINUX DO - 热门话题
Know Your Adversary
Know Your Adversary
Project Zero
Project Zero
D
Docker
L
Lohrmann on Cybersecurity
F
Full Disclosure

oida.dev | TypeScript, Rust

TypeScript's `erasableSyntaxOnly` Flag Unsafe for work Tokio: Macros Tokio: Channels Tokio: Getting Started Network Applications on the Tokio Stack Remake, Remodel, Reduce. The `never` type and error handling in TypeScript 5 Inconvenient Truths about TypeScript Refactoring in Rust: Introducing Traits Refactoring in Rust: Abstraction with the Newtype Pattern Announcing the TypeScript Cookbook TypeScript: Iterating over objects The road to universal JavaScript 10 years of oida.dev Rust: Tiny little traits The TypeScript converging point How not to learn TypeScript Getting started with Rust Introducing Slides and Coverage TypeScript: The humble function overload TypeScript + React: Children types are broken TypeScript: In defense of any Rust: Enums to wrap multiple errors Dissecting Deno Error handling in Rust TypeScript: Unexpected intersections Upgrading Node.js dependencies after a yarn audit TypeScript: Array.includes on narrow types TypeScript + React: Typing Generic forwardRefs shared, util, core: Schroedinger's module names Learning Rust and Go TypeScript: Narrow types in catch clauses TypeScript: Low maintenance types Tidy TypeScript: Name your generics Tidy TypeScript: Avoid traditional OOP patterns Tidy TypeScript: Prefer type aliases over interfaces Tidy TypeScript: Prefer union types over enums My new book: TypeScript in 50 Lessons Go Preact! ❤️ this in JavaScript and TypeScript TypeScript and ECMAScript Modules TypeScript + React: Why I don't use React.FC TypeScript + React: Component patterns TypeScript: Augmenting global and lib.dom.d.ts Vite with Preact and TypeScript TypeScript: Union to intersection type 11ty: Generate Twitter cards automatically Are large node module dependencies an issue? TypeScript: Variadic Tuple Types Preview TypeScript: Improving Object.keys Remake, Remodel. Part 4. TypeScript + React: Typing custom hooks with tuple types TypeScript: Assertion signatures and Object.defineProperty TypeScript: Check for object properties and narrow down type Boolean in JavaScript and TypeScript void in JavaScript and TypeScript Symbols in JavaScript and TypeScript Why I use TypeScript TypeScript + React: Extending JSX Elements TypeScript: Validate mapped types and const context TypeScript: Match the exact object shape TypeScript: The constructor interface pattern Streaming your Meetup - Part 4: Directing and Streaming with OBS Streaming your Meetup - Part 3: Speaker audio Streaming your Meetup - Part 2: Speaker video Streaming your Meetup - Part 1: Basics and Projector TypeScript and React Guide: Added a new styles chapter TypeScript and React Guide: Added a new render props chapter TypeScript and React: Styles and CSS TypeScript and React TypeScript and React Guide: Added a new prop types chapter TypeScript without TypeScript -- JSDoc superpowers TypeScript: Mapped types for type maps JAMStack vs serverless web apps The Unsung Benefits of JAMStack Sites TypeScript: Ambient modules for Webpack loaders My most favourite talks in 2018 TypeScript and React Guide: Added a new context chapter TypeScript: Built-in generic types TypeScript: Type predicates JSX is syntactic sugar TypeScript and React Guide: Added a new hooks chapter Getting your CfP application right FAQ on our Angular Connect Talk: Automating UI development TypeScript and Substitutability Debugging Node.js apps in TypeScript with Visual Studio Code From Medium: Deconfusing Pre- and Post-processing From Medium: PostCSS misconceptions Saving and scraping a website with Puppeteer Cutting the mustard - 2018 edition Wordpress as CMS for your JAMStack sites My most favourite podcast episodes in 2017 My most favourite talks in 2017 My most favourite books in 2017 The Best Request Is No Request, Revisited Not so hidden figures - Organizing ScriptConf My podcast journey to ScriptCast Grid layout, grid layout everywhere! #scriptconf and #devone
The magic of grunt-contrib-connect, and how to run PHP with it
2013-11-17 · via oida.dev | TypeScript, Rust

Note: This article is rather old. If you want to know more about `connect`, proceed, if you just want to have a PHP sever with livereload for your Grunt or Gulp setup, go there

One of the most loved Grunt.js extensions in our team is the ability to spawn a server for your project with the virtual push of a button, and to be able to see all the changes directly in the browser with a little Livereload magic. The seemingly endless Apache configuration days seemed to be over, and every front-end dev in our group was happy with the new workflow established. However, from time to time there was the urge to run some little PHP scripts. Not the big apps, mostly an inclusion of CMS managed labels. This need brought me to delve deeper into the mysteries of the connect task.

Behind every great task lies a great program: connect

What I like a lot about Grunt.js is the fact that it makes Node.js much more accessible. At least for me. I never spent any thought on learning this piece of software, but with the possibilities that Grunt.js brings for the workflow of a big front-end team, taking a look on server-side JavaScripting was inevitable. That's because Grunt.js in its very core just provides a structured and customisable interface to other Node.js programs underneath. The uglify task just starts Uglify.js, compass executes the Compass-Ruby gem, etc.

Same goes for connect. The task you install with grunt-contrib-connect just provides an interface to SenchaLab's Connect node module. Connect itself is a middleware framework for node's http package. Which means it comes with a lot of standard tasks which you need when creating a server.

Creating a server is already a rather simple task with node, but connect has some really neat built-in middleware for browsing a directory, serving files with the correct mime-type, handle sessions, etc. It also comes with a lot of third party middleware, one of the most popular ones being mentioned connect-livereload, or the proxy middleware we bespoke earlier on.

connect middleware

So how does this middleware tool work? Rather easy. Connect creates a stack of different middleware tasks and runs through this stack on every request taken. The middleware itself checks if it has something to do with this request, or if the request just has to be passed on to the next middleware in the stack.

The middleware stack is simply an array of middleware functions. To create a middleware for connect, you just have to implement the following interface:

```javascriptfunction myMiddleware(req, res, next) { //Magic happens } ```

The req and res object should be familiar with all of you who did create a server with the http module in node once. For all the others, in a nutshell: req represents the request, res the response, i.e. the stuff you want to appear in the browser.

next is a function which just calls the next middleware in the stack. Stephen Sugden wrote a good tutorial on creating middleware with really useful examples. So check that out if you want to know more on that topic.

grunt-contrib-connect uses two of the built-in middlwares and one third party middleware. Let's check out how it works:

```javascript middleware: function(connect, options) { var middlewares = []; var directory = options.directory || options.base[options.base.length - 1]; if (!Array.isArray(options.base)) { options.base = [options.base]; } options.base.forEach(function(base) { // Serve static files. middlewares.push(connect.static(base)); }); // Make directory browse-able. middlewares.push(connect.directory(directory)); return middlewares; } ```

Straight-forward, actually. It creates an array where to serve all static files in the defined base-directories (which can be an array of directories, but does not have to). It also uses connect.directory to make the main app directory browsable. This is the most basic server you can get.

Below it injects livereload. This tool has become so popular, it found its way into the official grunt-contrib-connect task.

```javascript // Inject live reload snippet if (options.livereload !== false) { if (options.livereload === true) { options.livereload = 35729; } //put livereload to the first place middleware.unshift(injectLiveReload({port: options.livereload})); } ```

So livereload takes every request, injects a JavaScript snippet when necessary and starts the livereload watcher to communicate between your browser and the the file system. Sweet.

At the time of this writing, it isn't possible to access the middleware array directly from your Gruntfile.js. But you can override the middleware function from the task, to create your very own stack of middleware for connect. Alas, this will kill the basic serving of directories and static files. So I suggest to reimplement the middleware function from above and insert your middleware snippets an the appropriate place. We'll get on to that below. The livereload option still will work whatsoever.

A PHP middleware

Before we continue, a quick disclaimer: Yeah, we are going to recreate the possibility of serving PHP files, but we won't be able to use all the server variables of PHP like $_SESSION or $_POST. Well, yet. I'm working on that issue, but for basic tasks this should work nonetheless.

So, to make PHP files parseable, we need to do two things:

  • Create a middleware that executes PHP
  • Include this middleware into our Grunt connect task

Even if it's kind of rough, the first part is actually really easy: Every time we get a request to a .php file, we call the php command line interface to parse this file, and write the result into our response:

```javascript function(req, res, next) { if(req.url.endsWith('.php')) { exec('php ' + directory + req.url, function callback(error, stdout, stderr){ if(error) { console.error(stderr); } res.write(stdout); res.end(); return; }); } else { // No .php file? Moving on ... next(); } } ```

This code snippet makes use of the exec module of node. The directory parameter points to the served folder in your filesystem. This code above lacks some initialisation methods, but you can install the whole middleware function from the NPM registry via

npm install connect-php

Include the new middleware in your Gruntfile.js

Always keep in mind that your Gruntfile.js is not only a configuration, but a JavaScript file. You can code there. And if necessary, you should!

So the first thing we are going to do is require our new module:

```javascript //Add this to the beginning of your Gruntfile.js var phpMiddleware = require('connect-php'); ```

Then, as mentioned above, we are going to recreate grunt-contrib-connect's middleware function, directly where you have your connect task:

```javascript grunt.initConfig({ ... connect: { options: { port: 9000, livereload: 35729, hostname: 'localhost', middleware: function(connect, options) { // Add here the code snippet below } }, ... } }); ``` ```javascript middleware: function(connect, options) { // Same as in grunt-contrib-connect var middlewares = []; var directory = options.directory || options.base[options.base.length - 1]; if (!Array.isArray(options.base)) { options.base = [options.base]; } // Here comes the PHP middleware middlewares.push(phpMiddleware(directory)); // Same as in grunt-contrib-connect options.base.forEach(function(base) { middlewares.push(connect.static(base)); }); middlewares.push(connect.directory(directory)); return middlewares; } ```

And that's it. You are now able to parse basic PHP files!

Bottom line

Actually, the whole PHP thing is just a way of showing you how to extend connect with middleware that serves your own needs. For us, the possibility of echo-ing and include-ing in PHP is enough to develop our website templates without having broken output while coding. It still lacks major features, but it's a good start. I'm thinking of reworking the script to tunnel all requests to a spawned PHP server to fill this gap, so stay tuned!

Trying to extend our developing environment with this certain feature taught me a lot about the mechanics behind Grunt.js and the Node.js cosmos behind that. I think it's the beauty of Grunt.js to demand nothing more than being a simple task runner for node tasks, and thus being exceptionally extensible. We didn't have this freedom and power with all the other build tools and developing environments we had before.

Related Articles