But Defi applications on Bitcoin will still be limited by its simple scripting abilities, so is it even possible to do Defi applications on Bitcoin?
Yes, but that simple scripting abilities are enough. If you can use Schnorr signatures, you can combine signatures together. So, if you can write something as a sum of public keys, then you can use Taproot. Probably even transactions could be written as public keys, if so, then the whole transactions could be combined in this way. For example: in multisig you need M-of-N keys, but you can also have N-of-N multisig and N-M signatures, in a typical transaction you have N inputs, so you need N signatures, you could for example own one private key and hold N-1 signatures, then you can move coins inside some second layer like the Lightning Network just by creating signatures!
The only limitation is expressing something as a public key. Many things can be expressed in this way, I can imagine for example Pedersen Commitments, where you have "rct=xG+aH(G)". You can just define "H(G)" as a public key where nobody knows any matching private key, multiply it by some blinding factor "a", and use some "x" you want to sum, multiplied by base point G. In this way you can join x'es in a provably fair way and "H(G)" will guarantee that as long as ECDSA is safe, nobody can take that coins alone.
Edit: Also note that Taproot is self-upgradeable. Now we have just the first version of Taproot, but there are many OP_SUCCESS opcodes, so I can imagine in the future some opcodes could be enabled again, for example OP_CAT or OP_SUBSTR. In general, I think that expressing something as a public key or introducing some new opcode is better than having Turing-complete Script, because then you can create opcodes fitting some particular purpose and do it more efficiently. In Ethereum you can do many things, but you have to repeat it over and over again on the blockchain, for me it's better to use "
OP_SOMETHING OP_2DROP" than revealing some complicated program with loops and many different conditions each time you want to do something unusual. It's just cheaper to push data, execute one-byte OP_SOMETHING and few bytes dropping that data (to maintain backward-compatibility where OP_SOMETHING was just OP_NOP) than push the whole program over and over again (also because loops are expensive).